MPEG4Writer.cpp revision acc47642e0f5d962f6289e6ba687fabf68f8312b
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
215e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    bool mIsRealTimeRecording;
216d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t mEstimatedTrackSizeBytes;
2171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t mMdatSizeBytes;
2188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mTimeScale;
21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
22020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
22120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
222be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
22313aec890216948b0c364f8f92792129d0335f506James Dong    List<MediaBuffer *> mChunkSamples;
2241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
225c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    bool                mSamplesHaveSameSize;
226c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStszTableEntries;
227be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
228c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStcoTableEntries;
229c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<off64_t> *mCo64TableEntries;
230c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStscTableEntries;
231c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStssTableEntries;
232c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mSttsTableEntries;
233c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mCttsTableEntries;
234965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
235000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t mMinCttsOffsetTimeUs;
236000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t mMaxCttsOffsetTimeUs;
237965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Sequence parameter set or picture parameter set
2393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    struct AVCParamSet {
2403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        AVCParamSet(uint16_t length, const uint8_t *data)
2413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            : mLength(length), mData(data) {}
2423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
2433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t mLength;
2443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *mData;
2453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    };
2463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mSeqParamSets;
2473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mPicParamSets;
2483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileIdc;
2493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileCompatible;
2503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mLevelIdc;
2513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
25220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
25320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
254548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    bool mGotAllCodecSpecificData;
25593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    bool mTrackingProgressStatus;
25620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
2583c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    int64_t mStartTimestampUs;
25970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mStartTimeRealUs;
26070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mFirstSampleTimeRealUs;
26193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mPreviousTrackTimeUs;
26293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mTrackEveryTimeDurationUs;
26325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
264872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Update the audio track's drift information.
265872a481558350634a3fd5cb67939de288af00ecbJames Dong    void updateDriftTime(const sp<MetaData>& meta);
266872a481558350634a3fd5cb67939de288af00ecbJames Dong
267000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int32_t getStartTimeOffsetScaledTime() const;
268000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
26920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
27037187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t threadEntry();
27120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *parseParamSet(
2733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
2743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
275b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
276b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
277b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
278215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
279215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Track authoring progress status
280faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    void trackProgressStatus(int64_t timeUs, status_t err = OK);
28193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    void initTrackingProgressStatus(MetaData *params);
28203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
28319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    void getCodecSpecificDataFromInputFormatIfPossible();
28419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
285c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Determine the track time scale
286c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If it is an audio track, try to use the sampling rate as
287c059860c73678a202bfa33062723e8f82fb779d9James Dong    // the time scale; however, if user chooses the overwrite
288c059860c73678a202bfa33062723e8f82fb779d9James Dong    // value, the user-supplied time scale will be used.
289c059860c73678a202bfa33062723e8f82fb779d9James Dong    void setTimeScale();
290c059860c73678a202bfa33062723e8f82fb779d9James Dong
291690f546b0ee548dbfe997df36418e5302ec2d786James Dong    // Simple validation on the codec specific data
292690f546b0ee548dbfe997df36418e5302ec2d786James Dong    status_t checkCodecSpecificData() const;
29313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t mRotation;
294690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void updateTrackSizeEstimate();
2961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
2971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStssTableEntry(size_t sampleId);
29879761ab096f57c3027fad9556c2bc436672d614eJames Dong
29979761ab096f57c3027fad9556c2bc436672d614eJames Dong    // Duration is time scale based
30079761ab096f57c3027fad9556c2bc436672d614eJames Dong    void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
301965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
30245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
30345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    bool isTrackMalFormed() const;
30443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    void sendTrackSummary(bool hasMultipleTracks);
3051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
306b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Write the boxes
307b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStcoBox(bool use32BitOffset);
308b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStscBox();
309b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStszBox();
310b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStssBox();
311b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSttsBox();
312965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    void writeCttsBox();
313b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeD263Box();
314b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writePaspBox();
315b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAvccBox();
316b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeUrlBox();
317b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDrefBox();
318b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDinfBox();
319b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDamrBox();
320efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    void writeMdhdBox(uint32_t now);
321b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSmhdBox();
322b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVmhdBox();
323b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeHdlrBox();
324efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    void writeTkhdBox(uint32_t now);
325b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4aEsdsBox();
326b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4vEsdsBox();
327b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAudioFourCCBox();
328b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVideoFourCCBox();
329b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStblBox(bool use32BitOffset);
330b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
33120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
33220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
33320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
33420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
33520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
336674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(-1),
337674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(NO_INIT),
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),
362b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
3631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
364a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
365a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
366a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
367411ba422e3635d534928ffd81abf54f4f291c739James Dong      mWriterThreadStarted(false),
36830ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
36913aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
3707837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
37107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mInterleaveDurationUs(1000000),
37207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLatitudex10000(0),
37307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLongitudex10000(0),
37486b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mAreGeoTagsAvailable(false),
37586b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mStartTimeOffsetMs(-1) {
37630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
37730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
37820111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
3798bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dong    reset();
38020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    while (!mTracks.empty()) {
3821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        List<Track *>::iterator it = mTracks.begin();
38320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
3841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        (*it) = NULL;
3851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mTracks.erase(it);
38620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
38720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
38820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
38920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
390dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump(
391dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) {
392dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
393dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
394dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
395dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
396dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
397dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
398dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
399dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
400dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    for (List<Track *>::iterator it = mTracks.begin();
401dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong         it != mTracks.end(); ++it) {
402dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        (*it)->dump(fd, args);
403dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    }
404dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
405dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
406dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
407dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump(
408dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) const {
409dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
410dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
411dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
412dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
413dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
414dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "       reached EOS: %s\n",
415dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong            mReachedEOS? "true": "false");
416dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
417c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    snprintf(buffer, SIZE, "       frames encoded : %d\n", mStszTableEntries->count());
41813210f3346462a86ce9fe3af72a0c200dba84e27James Dong    result.append(buffer);
41913210f3346462a86ce9fe3af72a0c200dba84e27James Dong    snprintf(buffer, SIZE, "       duration encoded : %lld us\n", mTrackDurationUs);
42013210f3346462a86ce9fe3af72a0c200dba84e27James Dong    result.append(buffer);
421dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
422dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
423dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
424dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
4252dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
426bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Mutex::Autolock l(mLock);
427bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    if (mStarted) {
42829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Attempt to add source AFTER recording is started");
429bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        return UNKNOWN_ERROR;
430bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    }
431acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
432acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // At most 2 tracks can be supported.
433acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    if (mTracks.size() >= 2) {
434acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        ALOGE("Too many tracks (%d) to add", mTracks.size());
435acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        return ERROR_UNSUPPORTED;
436acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
437acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
438acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    CHECK(source.get() != NULL);
439acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
440acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // A track of type other than video or audio is not supported.
441acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    const char *mime;
442acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    source->getFormat()->findCString(kKeyMIMEType, &mime);
443acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    bool isAudio = !strncasecmp(mime, "audio/", 6);
444acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    bool isVideo = !strncasecmp(mime, "video/", 6);
445acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    if (!isAudio && !isVideo) {
446acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        ALOGE("Track (%s) other than video or audio is not supported",
447acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong            mime);
448acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        return ERROR_UNSUPPORTED;
449acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
450acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
451acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // At this point, we know the track to be added is either
452acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // video or audio. Thus, we only need to check whether it
453acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // is an audio track or not (if it is not, then it must be
454acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // a video track).
455acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
456acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // No more than one video or one audio track is supported.
457acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    for (List<Track*>::iterator it = mTracks.begin();
458acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong         it != mTracks.end(); ++it) {
459acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        if ((*it)->isAudio() == isAudio) {
460acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong            ALOGE("%s track already exists", isAudio? "Audio": "Video");
461acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong            return ERROR_UNSUPPORTED;
462acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        }
463acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
464acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
465acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // This is the first track of either audio or video.
466acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // Go ahead to add the track.
467219f195159f93d627af2b243732e3f9020511a46James Dong    Track *track = new Track(this, source, 1 + mTracks.size());
46820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
4692dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
4702dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
47120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
47220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
47393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) {
474acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    if (mTracks.empty()) {
475acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        ALOGE("No source added");
476acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        return INVALID_OPERATION;
477acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
478acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
479a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
480a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
48193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        status_t err = (*it)->start(params);
482a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
483a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (err != OK) {
484a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            for (List<Track *>::iterator it2 = mTracks.begin();
485a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                 it2 != it; ++it2) {
486a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                (*it2)->stop();
487a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            }
488a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
489a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            return err;
490a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
491a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
492a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
493a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
494a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
4952dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
4962dec2b5be2056c6d9428897dc672185872d30d17James Dong    // This implementation is highly experimental/heurisitic.
4972dec2b5be2056c6d9428897dc672185872d30d17James Dong    //
4982dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Statistical analysis shows that metadata usually accounts
4992dec2b5be2056c6d9428897dc672185872d30d17James Dong    // for a small portion of the total file size, usually < 0.6%.
5002dec2b5be2056c6d9428897dc672185872d30d17James Dong
50178a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
5022dec2b5be2056c6d9428897dc672185872d30d17James Dong    // where 1MB is the common file size limit for MMS application.
50378a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MAX _MOOV_BOX_SIZE value is based on about 3
5042dec2b5be2056c6d9428897dc672185872d30d17James Dong    // minute video recording with a bit rate about 3 Mbps, because
5052dec2b5be2056c6d9428897dc672185872d30d17James Dong    // statistics also show that most of the video captured are going
5062dec2b5be2056c6d9428897dc672185872d30d17James Dong    // to be less than 3 minutes.
5072dec2b5be2056c6d9428897dc672185872d30d17James Dong
5082dec2b5be2056c6d9428897dc672185872d30d17James Dong    // If the estimation is wrong, we will pay the price of wasting
5092dec2b5be2056c6d9428897dc672185872d30d17James Dong    // some reserved space. This should not happen so often statistically.
5102dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int32_t factor = mUse32BitOffset? 1: 2;
51178a1a286f736888ae7af8860b2c424af0d978848James Dong    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
5122dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
5132dec2b5be2056c6d9428897dc672185872d30d17James Dong    int64_t size = MIN_MOOV_BOX_SIZE;
5142dec2b5be2056c6d9428897dc672185872d30d17James Dong
51578a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file size limit is set
516a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
51778a1a286f736888ae7af8860b2c424af0d978848James Dong        size = mMaxFileSizeLimitBytes * 6 / 1000;
51878a1a286f736888ae7af8860b2c424af0d978848James Dong    }
51978a1a286f736888ae7af8860b2c424af0d978848James Dong
52078a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file duration limit is set
52178a1a286f736888ae7af8860b2c424af0d978848James Dong    if (mMaxFileDurationLimitUs != 0) {
52278a1a286f736888ae7af8860b2c424af0d978848James Dong        if (bitRate > 0) {
52378a1a286f736888ae7af8860b2c424af0d978848James Dong            int64_t size2 =
52478a1a286f736888ae7af8860b2c424af0d978848James Dong                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
52578a1a286f736888ae7af8860b2c424af0d978848James Dong            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
52678a1a286f736888ae7af8860b2c424af0d978848James Dong                // When both file size and duration limits are set,
52778a1a286f736888ae7af8860b2c424af0d978848James Dong                // we use the smaller limit of the two.
52878a1a286f736888ae7af8860b2c424af0d978848James Dong                if (size > size2) {
52978a1a286f736888ae7af8860b2c424af0d978848James Dong                    size = size2;
53078a1a286f736888ae7af8860b2c424af0d978848James Dong                }
53178a1a286f736888ae7af8860b2c424af0d978848James Dong            } else {
53278a1a286f736888ae7af8860b2c424af0d978848James Dong                // Only max file duration limit is set
53378a1a286f736888ae7af8860b2c424af0d978848James Dong                size = size2;
53478a1a286f736888ae7af8860b2c424af0d978848James Dong            }
5352dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
5362dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
53778a1a286f736888ae7af8860b2c424af0d978848James Dong
5382dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size < MIN_MOOV_BOX_SIZE) {
5392dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MIN_MOOV_BOX_SIZE;
5402dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5412dec2b5be2056c6d9428897dc672185872d30d17James Dong
5422dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Any long duration recording will be probably end up with
5432dec2b5be2056c6d9428897dc672185872d30d17James Dong    // non-streamable mp4 file.
5442dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size > MAX_MOOV_BOX_SIZE) {
5452dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MAX_MOOV_BOX_SIZE;
5462dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5472dec2b5be2056c6d9428897dc672185872d30d17James Dong
548df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
5492dec2b5be2056c6d9428897dc672185872d30d17James Dong         " moov size %lld bytes",
5502dec2b5be2056c6d9428897dc672185872d30d17James Dong         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
5512dec2b5be2056c6d9428897dc672185872d30d17James Dong    return factor * size;
5522dec2b5be2056c6d9428897dc672185872d30d17James Dong}
5532dec2b5be2056c6d9428897dc672185872d30d17James Dong
5542dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) {
555674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
55625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
55720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
55820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
559a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    /*
560a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * Check mMaxFileSizeLimitBytes at the beginning
561a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * since mMaxFileSizeLimitBytes may be implicitly
562a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * changed later for 32-bit file offset even if
563a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * user does not ask to set it explicitly.
564a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     */
565a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0) {
566a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong        mIsFileSizeLimitExplicitlyRequested = true;
567a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    }
568a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong
5692dec2b5be2056c6d9428897dc672185872d30d17James Dong    int32_t use64BitOffset;
5702dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (param &&
5712dec2b5be2056c6d9428897dc672185872d30d17James Dong        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
5722dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64BitOffset) {
5732dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
5742dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5752dec2b5be2056c6d9428897dc672185872d30d17James Dong
5761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    if (mUse32BitOffset) {
5771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // Implicit 32 bit file size limit
5781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes == 0) {
5791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
5801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
5811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
5821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // If file size is set to be larger than the 32 bit file
5831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // size limit, treat it as an error.
5841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
5855ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block            ALOGW("32-bit file size limit (%lld bytes) too big. "
586d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                 "It is changed to %lld bytes",
587d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                mMaxFileSizeLimitBytes, kMax32BitFileSize);
588d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
5891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
5901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    }
5911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
592b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    int32_t use2ByteNalLength;
593b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (param &&
594b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
595b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        use2ByteNalLength) {
596b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mUse4ByteNalLength = false;
5972dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5982dec2b5be2056c6d9428897dc672185872d30d17James Dong
599065d1aff96818df54456053f1574aec8a234d0deJames Dong    mStartTimestampUs = -1;
60093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
601a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mStarted) {
602a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused) {
603a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mPaused = false;
60493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return startTracks(param);
605a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
606a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
607a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
608a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
6098f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (!param ||
6108f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
6118f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mTimeScale = 1000;
6128f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
61343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mTimeScale, 0);
6143856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("movie time scale: %d", mTimeScale);
6158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
61677e8ae9967a078770416619e99ddb5b010def312James Dong    /*
61777e8ae9967a078770416619e99ddb5b010def312James Dong     * When the requested file size limit is small, the priority
61877e8ae9967a078770416619e99ddb5b010def312James Dong     * is to meet the file size limit requirement, rather than
6197b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * to make the file streamable. mStreamableFile does not tell
6207b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * whether the actual recorded file is streamable or not.
62177e8ae9967a078770416619e99ddb5b010def312James Dong     */
62277e8ae9967a078770416619e99ddb5b010def312James Dong    mStreamableFile =
62377e8ae9967a078770416619e99ddb5b010def312James Dong        (mMaxFileSizeLimitBytes != 0 &&
62477e8ae9967a078770416619e99ddb5b010def312James Dong         mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
62577e8ae9967a078770416619e99ddb5b010def312James Dong
6267b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    /*
6277b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * mWriteMoovBoxToMemory is true if the amount of data in moov box is
6287b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * smaller than the reserved free space at the beginning of a file, AND
6297b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * when the content of moov box is constructed. Note that video/audio
6307b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * frame data is always written to the file but not in the memory.
6317b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6327b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * Before stop()/reset() is called, mWriteMoovBoxToMemory is always
6337b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * false. When reset() is called at the end of a recording session,
6347b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * Moov box needs to be constructed.
6357b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6367b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory
6377b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * to set to mStreamableFile so that if
6387b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * the file is intended to be streamable, it is set to true;
6397b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * otherwise, it is set to false. When the value is set to false,
6407b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * all the content of the moov box is written immediately to
6417b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * the end of the file. When the value is set to true, all the
6427b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * content of the moov box is written to an in-memory cache,
6437b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * mMoovBoxBuffer, util the following condition happens. Note
6447b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * that the size of the in-memory cache is the same as the
6457b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * reserved free space at the beginning of the file.
6467b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6477b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * 2) While the data of the moov box is written to an in-memory
6487b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * cache, the data size is checked against the reserved space.
6497b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * If the data size surpasses the reserved space, subsequent moov
6507b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * data could no longer be hold in the in-memory cache. This also
6517b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * indicates that the reserved space was too small. At this point,
6527b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * _all_ moov data must be written to the end of the file.
6537b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * mWriteMoovBoxToMemory must be set to false to direct the write
6547b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * to the file.
6557b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6567b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * 3) If the data size in moov box is smaller than the reserved
6577b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * space after moov box is completely constructed, the in-memory
6587b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * cache copy of the moov box is written to the reserved free
6597b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * space. Thus, immediately after the moov is completedly
6607b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * constructed, mWriteMoovBoxToMemory is always set to false.
6617b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     */
6627b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    mWriteMoovBoxToMemory = false;
6637837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = NULL;
6647837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
6657837c17063a4c50bc856ba59418516fdab731de7James Dong
666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFtypBox(param);
66720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6687837c17063a4c50bc856ba59418516fdab731de7James Dong    mFreeBoxOffset = mOffset;
66920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6707837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mEstimatedMoovBoxSize == 0) {
6712dec2b5be2056c6d9428897dc672185872d30d17James Dong        int32_t bitRate = -1;
6722dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (param) {
6732dec2b5be2056c6d9428897dc672185872d30d17James Dong            param->findInt32(kKeyBitRate, &bitRate);
6742dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
6752dec2b5be2056c6d9428897dc672185872d30d17James Dong        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
6767837c17063a4c50bc856ba59418516fdab731de7James Dong    }
67743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(mEstimatedMoovBoxSize, 8);
67877e8ae9967a078770416619e99ddb5b010def312James Dong    if (mStreamableFile) {
67977e8ae9967a078770416619e99ddb5b010def312James Dong        // Reserve a 'free' box only for streamable file
68077e8ae9967a078770416619e99ddb5b010def312James Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
68177e8ae9967a078770416619e99ddb5b010def312James Dong        writeInt32(mEstimatedMoovBoxSize);
68277e8ae9967a078770416619e99ddb5b010def312James Dong        write("free", 4);
68377e8ae9967a078770416619e99ddb5b010def312James Dong        mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
68477e8ae9967a078770416619e99ddb5b010def312James Dong    } else {
68577e8ae9967a078770416619e99ddb5b010def312James Dong        mMdatOffset = mOffset;
68677e8ae9967a078770416619e99ddb5b010def312James Dong    }
6877837c17063a4c50bc856ba59418516fdab731de7James Dong
6887837c17063a4c50bc856ba59418516fdab731de7James Dong    mOffset = mMdatOffset;
689c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mMdatOffset, SEEK_SET);
6901acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
6911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("????mdat", 8);
6921acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
6931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("\x00\x00\x00\x01mdat????????", 16);
6941acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
6951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
6961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    status_t err = startWriterThread();
6971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (err != OK) {
6981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return err;
6991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
7001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    err = startTracks(param);
702a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (err != OK) {
703a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return err;
70420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
7051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
706a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = true;
70725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
70920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const {
7111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    return mUse32BitOffset;
7121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
7131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
71437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() {
715674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
71637187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
717a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
718a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
71937187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
720a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
721a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
72237187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->pause();
72337187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (status != OK) {
72437187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
72537187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
726a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
72737187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
728a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
729a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
7301c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() {
731b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping writer thread");
732411ba422e3635d534928ffd81abf54f4f291c739James Dong    if (!mWriterThreadStarted) {
733411ba422e3635d534928ffd81abf54f4f291c739James Dong        return;
734411ba422e3635d534928ffd81abf54f4f291c739James Dong    }
7351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
7371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
7381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mDone = true;
7401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkReadyCondition.signal();
7411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
7421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void *dummy;
7441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_join(mThread, &dummy);
745411ba422e3635d534928ffd81abf54f4f291c739James Dong    mWriterThreadStarted = false;
746b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Writer thread stopped");
7471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
7481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
74913f6284305e4b27395a23db7882d670bdb1bcae1James Dong/*
75013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix:
75113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a  b  u |
75213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c  d  v |
75313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x  y  w |
75413f6284305e4b27395a23db7882d670bdb1bcae1James Dong *
75513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following
75613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w},
75713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while
75813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format.
75913f6284305e4b27395a23db7882d670bdb1bcae1James Dong */
76013f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) {
7613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeCompositionMatrix");
76213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t a = 0x00010000;
76313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t b = 0;
76413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t c = 0;
76513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t d = 0x00010000;
76613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    switch (degrees) {
76713f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 0:
76813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
76913f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 90:
77013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
77113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0x00010000;
77213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0xFFFF0000;
77313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
77413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
77513f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 180:
77613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0xFFFF0000;
77713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0xFFFF0000;
77813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
77913f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 270:
78013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
78113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0xFFFF0000;
78213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0x00010000;
78313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
78413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
78513f6284305e4b27395a23db7882d670bdb1bcae1James Dong        default:
78613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            CHECK(!"Should never reach this unknown rotation");
78713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
78813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
78913f6284305e4b27395a23db7882d670bdb1bcae1James Dong
79013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(a);           // a
79113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(b);           // b
79213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // u
79313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(c);           // c
79413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(d);           // d
79513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // v
79613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // x
79713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // y
79813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0x40000000);  // w
79913f6284305e4b27395a23db7882d670bdb1bcae1James Dong}
80013f6284305e4b27395a23db7882d670bdb1bcae1James Dong
801411ba422e3635d534928ffd81abf54f4f291c739James Dongvoid MPEG4Writer::release() {
802411ba422e3635d534928ffd81abf54f4f291c739James Dong    close(mFd);
803411ba422e3635d534928ffd81abf54f4f291c739James Dong    mFd = -1;
804411ba422e3635d534928ffd81abf54f4f291c739James Dong    mInitCheck = NO_INIT;
805411ba422e3635d534928ffd81abf54f4f291c739James Dong    mStarted = false;
806411ba422e3635d534928ffd81abf54f4f291c739James Dong}
80713f6284305e4b27395a23db7882d670bdb1bcae1James Dong
8088bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dongstatus_t MPEG4Writer::reset() {
809674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
81037187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
811411ba422e3635d534928ffd81abf54f4f291c739James Dong    } else {
812411ba422e3635d534928ffd81abf54f4f291c739James Dong        if (!mWriterThreadStarted ||
813411ba422e3635d534928ffd81abf54f4f291c739James Dong            !mStarted) {
814411ba422e3635d534928ffd81abf54f4f291c739James Dong            if (mWriterThreadStarted) {
815411ba422e3635d534928ffd81abf54f4f291c739James Dong                stopWriterThread();
816411ba422e3635d534928ffd81abf54f4f291c739James Dong            }
817411ba422e3635d534928ffd81abf54f4f291c739James Dong            release();
818411ba422e3635d534928ffd81abf54f4f291c739James Dong            return OK;
819411ba422e3635d534928ffd81abf54f4f291c739James Dong        }
82020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
82120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
82237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
8238f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t maxDurationUs = 0;
82465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    int64_t minDurationUs = 0x7fffffffffffffffLL;
82520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
82620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
82737187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->stop();
82837187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK) {
82937187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
83037187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int64_t durationUs = (*it)->getDurationUs();
8338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (durationUs > maxDurationUs) {
8348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            maxDurationUs = durationUs;
83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
83665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        if (durationUs < minDurationUs) {
83765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs = durationUs;
83865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        }
83965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    }
84065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong
84165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    if (mTracks.size() > 1) {
842b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("Duration from tracks range is [%lld, %lld] us",
84365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs, maxDurationUs);
84420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
84520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    stopWriterThread();
8477837c17063a4c50bc856ba59418516fdab731de7James Dong
84837187916a486504acaf83bea30147eb5fbf46ae5James Dong    // Do not write out movie header on error.
84937187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err != OK) {
850411ba422e3635d534928ffd81abf54f4f291c739James Dong        release();
85137187916a486504acaf83bea30147eb5fbf46ae5James Dong        return err;
85237187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
85337187916a486504acaf83bea30147eb5fbf46ae5James Dong
85420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
8551acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
856c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset, SEEK_SET);
8571acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
858c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 4);
8591acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
860c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
8611acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int64_t size = mOffset - mMdatOffset;
8621acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        size = hton64(size);
863c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 8);
8641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
865c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mOffset, SEEK_SET);
86620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8677b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // Construct moov box now
8687837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
8697b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    mWriteMoovBoxToMemory = mStreamableFile;
8707b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    if (mWriteMoovBoxToMemory) {
8717b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // There is no need to allocate in-memory cache
8727b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // for moov box if the file is not streamable.
8737b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
8747b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
8757b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        CHECK(mMoovBoxBuffer != NULL);
8767b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    }
877b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMoovBox(maxDurationUs);
87820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8797b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // mWriteMoovBoxToMemory could be set to false in
8807b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // MPEG4Writer::write() method
8817b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    if (mWriteMoovBoxToMemory) {
8827b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        mWriteMoovBoxToMemory = false;
8837b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // Content of the moov box is saved in the cache, and the in-memory
8847b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // moov box needs to be written to the file in a single shot.
8857b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
88643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
8877837c17063a4c50bc856ba59418516fdab731de7James Dong
8887837c17063a4c50bc856ba59418516fdab731de7James Dong        // Moov box
889c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
8907837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset = mFreeBoxOffset;
891674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
8927837c17063a4c50bc856ba59418516fdab731de7James Dong
8937837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free box
894c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
8957837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
8967837c17063a4c50bc856ba59418516fdab731de7James Dong        write("free", 4);
8977b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    } else {
8987b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        ALOGI("The mp4 file will not be streamable.");
8997b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    }
9007837c17063a4c50bc856ba59418516fdab731de7James Dong
9017b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // Free in-memory cache for moov box
9027b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    if (mMoovBoxBuffer != NULL) {
9037837c17063a4c50bc856ba59418516fdab731de7James Dong        free(mMoovBoxBuffer);
9047837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBuffer = NULL;
9057837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBufferOffset = 0;
9067837c17063a4c50bc856ba59418516fdab731de7James Dong    }
9077837c17063a4c50bc856ba59418516fdab731de7James Dong
9080c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
910411ba422e3635d534928ffd81abf54f4f291c739James Dong    release();
91137187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
91220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
91320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
914efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonuint32_t MPEG4Writer::getMpeg4Time() {
915b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    time_t now = time(NULL);
916efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    // MP4 file uses time counting seconds since midnight, Jan. 1, 1904
917efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    // while time function returns Unix epoch values which starts
918efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    // at 1970-01-01. Lets add the number of seconds between them
919efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60);
920efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    return mpeg4Time;
921efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson}
922efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson
923efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) {
924efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    uint32_t now = getMpeg4Time();
925b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("mvhd");
926b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // version=0, flags=0
927b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // creation time
928b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // modification time
929b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTimeScale);    // mvhd timescale
930b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
931b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(duration);
932b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0x10000);       // rate: 1.0
933b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0x100);         // volume
934b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0);             // reserved
935b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
936b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
937b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeCompositionMatrix(0); // matrix
938b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
939b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
940b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
941b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
942b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
943b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
944b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTracks.size() + 1);  // nextTrackID
945b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // mvhd
946b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
947b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
948b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) {
949b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("moov");
950b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMvhdBox(durationUs);
95107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (mAreGeoTagsAvailable) {
95207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        writeUdtaBox();
95307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
954b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t id = 1;
955b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<Track *>::iterator it = mTracks.begin();
956b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mTracks.end(); ++it, ++id) {
957b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (*it)->writeTrackHeader(mUse32BitOffset);
958b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
959b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // moov
960b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
961b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
9622cf9c5073ca3342ee52673ad68763fadd2c2be79James Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) {
963b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("ftyp");
964b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
965b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t fileType;
966b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (param && param->findInt32(kKeyFileType, &fileType) &&
967b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fileType != OUTPUT_FORMAT_MPEG_4) {
968b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("3gp4");
969b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
970b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("isom");
971b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
972b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
973b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);
974b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("isom");
975b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("3gp4");
976b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();
977b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
978b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
97907ec01904613a0bac32caaa8444b4690998faed7James Dongstatic bool isTestModeEnabled() {
98007ec01904613a0bac32caaa8444b4690998faed7James Dong#if (PROPERTY_VALUE_MAX < 5)
98107ec01904613a0bac32caaa8444b4690998faed7James Dong#error "PROPERTY_VALUE_MAX must be at least 5"
98207ec01904613a0bac32caaa8444b4690998faed7James Dong#endif
98307ec01904613a0bac32caaa8444b4690998faed7James Dong
98407ec01904613a0bac32caaa8444b4690998faed7James Dong    // Test mode is enabled only if rw.media.record.test system
98507ec01904613a0bac32caaa8444b4690998faed7James Dong    // property is enabled.
98607ec01904613a0bac32caaa8444b4690998faed7James Dong    char value[PROPERTY_VALUE_MAX];
98707ec01904613a0bac32caaa8444b4690998faed7James Dong    if (property_get("rw.media.record.test", value, NULL) &&
98807ec01904613a0bac32caaa8444b4690998faed7James Dong        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
98907ec01904613a0bac32caaa8444b4690998faed7James Dong        return true;
99007ec01904613a0bac32caaa8444b4690998faed7James Dong    }
99107ec01904613a0bac32caaa8444b4690998faed7James Dong    return false;
99207ec01904613a0bac32caaa8444b4690998faed7James Dong}
99307ec01904613a0bac32caaa8444b4690998faed7James Dong
99470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() {
99507ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send session summary only if test mode is enabled
99607ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
99707ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
99807ec01904613a0bac32caaa8444b4690998faed7James Dong    }
99907ec01904613a0bac32caaa8444b4690998faed7James Dong
100070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
100170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong         it != mChunkInfos.end(); ++it) {
100270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int trackNum = it->mTrack->getTrackId() << 28;
100370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
100470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
100570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs);
100670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    }
100770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong}
100870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
100913aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
101013aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
101113aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
101213aec890216948b0c364f8f92792129d0335f506James Dong}
101313aec890216948b0c364f8f92792129d0335f506James Dong
101413aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() {
101513aec890216948b0c364f8f92792129d0335f506James Dong    mLock.lock();
101613aec890216948b0c364f8f92792129d0335f506James Dong}
101713aec890216948b0c364f8f92792129d0335f506James Dong
101813aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() {
101913aec890216948b0c364f8f92792129d0335f506James Dong    mLock.unlock();
102013aec890216948b0c364f8f92792129d0335f506James Dong}
102120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1022c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
1023c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
102420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1025c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    ::write(mFd,
1026c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          (const uint8_t *)buffer->data() + buffer->range_offset(),
1027c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          buffer->range_length());
102820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
102920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
103020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
103120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
103220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
103320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
103403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
103503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
103603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
103703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
103803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
103903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
104003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
104103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
104203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
104303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
104403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
104503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
104603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
104703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1048c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
1049c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
105030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
105130ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
105203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1053b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mUse4ByteNalLength) {
1054b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 24;
1055c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1056b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 16) & 0xff;
1057c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1058b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 8) & 0xff;
1059c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1060b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
1061c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1062c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong
1063c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd,
1064c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              (const uint8_t *)buffer->data() + buffer->range_offset(),
1065c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              length);
1066b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
1067b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 4;
1068b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
106943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_LT(length, 65536);
107030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1071b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 8;
1072c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1073b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
1074c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1075c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
1076b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 2;
1077b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
107830ab66297501757d745b9ae10da61adcd891f497Andreas Huber
107930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
108030ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
108130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
10827837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write(
1083674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        const void *ptr, size_t size, size_t nmemb) {
10847837c17063a4c50bc856ba59418516fdab731de7James Dong
10857837c17063a4c50bc856ba59418516fdab731de7James Dong    const size_t bytes = size * nmemb;
10867837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
10877b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
1088c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
10891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        if (moovBoxSize > mEstimatedMoovBoxSize) {
10907b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // The reserved moov box at the beginning of the file
10917b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // is not big enough. Moov box should be written to
10927b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // the end of the file from now on, but not to the
10937b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // in-memory cache.
10947b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
10957b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // We write partial moov box that is in the memory to
10967b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // the file first.
1097c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            for (List<off64_t>::iterator it = mBoxes.begin();
10987837c17063a4c50bc856ba59418516fdab731de7James Dong                 it != mBoxes.end(); ++it) {
10997837c17063a4c50bc856ba59418516fdab731de7James Dong                (*it) += mOffset;
11007837c17063a4c50bc856ba59418516fdab731de7James Dong            }
1101674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            lseek64(mFd, mOffset, SEEK_SET);
1102674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
11037b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            ::write(mFd, ptr, bytes);
11047837c17063a4c50bc856ba59418516fdab731de7James Dong            mOffset += (bytes + mMoovBoxBufferOffset);
11057b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
11067b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // All subsequent moov box content will be written
11077b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // to the end of the file.
11087837c17063a4c50bc856ba59418516fdab731de7James Dong            mWriteMoovBoxToMemory = false;
11097837c17063a4c50bc856ba59418516fdab731de7James Dong        } else {
11107837c17063a4c50bc856ba59418516fdab731de7James Dong            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
11117837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset += bytes;
11127837c17063a4c50bc856ba59418516fdab731de7James Dong        }
11137837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
1114674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        ::write(mFd, ptr, size * nmemb);
11157837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset += bytes;
11167837c17063a4c50bc856ba59418516fdab731de7James Dong    }
11177837c17063a4c50bc856ba59418516fdab731de7James Dong    return bytes;
11187837c17063a4c50bc856ba59418516fdab731de7James Dong}
11197837c17063a4c50bc856ba59418516fdab731de7James Dong
112020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
11210c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
112220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
11237837c17063a4c50bc856ba59418516fdab731de7James Dong    mBoxes.push_back(mWriteMoovBoxToMemory?
11247837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset: mOffset);
112520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
112620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
112720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
112820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
112920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
113020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
11310c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
113220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1133c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t offset = *--mBoxes.end();
113420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
113520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
11367837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
11377837c17063a4c50bc856ba59418516fdab731de7James Dong       int32_t x = htonl(mMoovBoxBufferOffset - offset);
11387837c17063a4c50bc856ba59418516fdab731de7James Dong       memcpy(mMoovBoxBuffer + offset, &x, 4);
11397837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
1140c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, offset, SEEK_SET);
11417837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mOffset - offset);
11427837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset -= 4;
1143c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
11447837c17063a4c50bc856ba59418516fdab731de7James Dong    }
114520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
114620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
114720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
1148674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 1);
114920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
115020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
115120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
115220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
1153674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 2);
115420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
115520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
115620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
115720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
1158674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 4);
115920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
116020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
116120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
116220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
1163674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 8);
116420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
116520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
116620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
116720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
1168674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, n + 1);
116920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
117020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
117120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
11720c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
1173674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, 4);
117420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
117520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
117607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
117707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format
117807b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) {
117907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
118007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
118107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
118207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
118307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[9];
118407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
118507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
118607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%c%.2d.", sign, wholePart);
118707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
118807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%+.2d.", wholePart);
118907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
119007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
119107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
119207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
119307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
119407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
119507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
119607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[4], 5, "%.4d", fractionalPart);
119707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
119807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
119907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 8);
120007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
120107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
120207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format
120307b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) {
120407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
120507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
120607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
120707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
120807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[10];
120907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
121007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
121107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%c%.3d.", sign, wholePart);
121207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
121307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%+.3d.", wholePart);
121407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
121507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
121607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
121707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
121807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
121907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
122007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
122107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[5], 5, "%.4d", fractionalPart);
122207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
122307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
122407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 9);
122507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
122607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
122707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
122807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
122907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and
123007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000.
123107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and
123207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180]
123307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
123407b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
123507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Is latitude or longitude out of range?
123607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
123707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        longitudex10000 < -1800000 || longitudex10000 > 1800000) {
123807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        return BAD_VALUE;
123907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
124007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
124107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLatitudex10000 = latitudex10000;
124207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLongitudex10000 = longitudex10000;
124307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mAreGeoTagsAvailable = true;
124407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    return OK;
124507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
124607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
124720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
1248674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(data, 1, size);
124920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
125020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
125178a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const {
125278a1a286f736888ae7af8860b2c424af0d978848James Dong    return mStreamableFile;
125378a1a286f736888ae7af8860b2c424af0d978848James Dong}
125478a1a286f736888ae7af8860b2c424af0d978848James Dong
1255d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() {
1256d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1257d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeLimitBytes == 0) {
1258d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1259d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1260d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1261956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
1262d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1263d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1264d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
1265d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
12661f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
126777e8ae9967a078770416619e99ddb5b010def312James Dong    if (!mStreamableFile) {
126877e8ae9967a078770416619e99ddb5b010def312James Dong        // Add 1024 bytes as error tolerance
126977e8ae9967a078770416619e99ddb5b010def312James Dong        return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
127077e8ae9967a078770416619e99ddb5b010def312James Dong    }
1271acd234bba9f048971d66890009eeff9a8db94be3James Dong    // Be conservative in the estimate: do not exceed 95% of
1272acd234bba9f048971d66890009eeff9a8db94be3James Dong    // the target file limit. For small target file size limit, though,
1273acd234bba9f048971d66890009eeff9a8db94be3James Dong    // this will not help.
1274acd234bba9f048971d66890009eeff9a8db94be3James Dong    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
1275d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1276d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1277d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() {
1278d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1279d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationLimitUs == 0) {
1280d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1281d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1282d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1283d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1284d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1285d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
1286d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            return true;
1287d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1288d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1289d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return false;
1290d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1291d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
129225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
129325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
129425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
129525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
129625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
129725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
129825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
129925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
130025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
130125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
130225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
130325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
130425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
1305f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
1306df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("setStartTimestampUs: %lld", timeUs);
130743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(timeUs, 0ll);
13083c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
1309065d1aff96818df54456053f1574aec8a234d0deJames Dong    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
1310f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimestampUs = timeUs;
1311df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Earliest track starting time: %lld", mStartTimestampUs);
13123c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    }
13133c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
13143c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
1315f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() {
13163c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
13173c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    return mStartTimestampUs;
13183c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
13193c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
132058ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() {
132158ae9c530247668f8af36e30d228c716c226b3d4James Dong    Mutex::Autolock autolock(mLock);
132258ae9c530247668f8af36e30d228c716c226b3d4James Dong    return mTracks.size();
132358ae9c530247668f8af36e30d228c716c226b3d4James Dong}
132458ae9c530247668f8af36e30d228c716c226b3d4James Dong
132520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
132620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
132720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
1328bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
132920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
133025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
133120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
133220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
1333a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
1334a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mResumed(false),
1335eaae38445a340c4857c1c5569475879a728e63b7James Dong      mStarted(false),
1336bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong      mTrackId(trackId),
1337c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong      mTrackDurationUs(0),
1338956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      mEstimatedTrackSizeBytes(0),
1339be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong      mSamplesHaveSameSize(true),
1340c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1341c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1342c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)),
1343c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)),
1344c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1345c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
1346c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
134720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
134825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
1349548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber      mGotAllCodecSpecificData(false),
135013f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mReachedEOS(false),
135113f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mRotation(0) {
135219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    getCodecSpecificDataFromInputFormatIfPossible();
13538f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
13541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    const char *mime;
13551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMeta->findCString(kKeyMIMEType, &mime);
13561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
13571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAudio = !strncasecmp(mime, "audio/", 6);
13581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
13591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
13601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1361c059860c73678a202bfa33062723e8f82fb779d9James Dong    setTimeScale();
1362c059860c73678a202bfa33062723e8f82fb779d9James Dong}
1363c059860c73678a202bfa33062723e8f82fb779d9James Dong
13641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() {
13651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1366c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
1367c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                            ? mStcoTableEntries->count()
1368c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                            : mCo64TableEntries->count());
1369c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
1370c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
13711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
137278a1a286f736888ae7af8860b2c424af0d978848James Dong    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
137378a1a286f736888ae7af8860b2c424af0d978848James Dong    if (!mOwner->isFileStreamable()) {
137478a1a286f736888ae7af8860b2c424af0d978848James Dong        // Reserved free space is not large enough to hold
137578a1a286f736888ae7af8860b2c424af0d978848James Dong        // all meta data and thus wasted.
1376c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 +  // stsc box size
1377c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                                    mStssTableEntries->count() * 4 +   // stss box size
1378c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                                    mSttsTableEntries->count() * 8 +   // stts box size
1379c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                                    mCttsTableEntries->count() * 8 +   // ctts box size
138078a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stcoBoxSizeBytes +           // stco box size
138178a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stszBoxSizeBytes;            // stsz box size
138278a1a286f736888ae7af8860b2c424af0d978848James Dong    }
13831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
13841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
13851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry(
13861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t chunkId, size_t sampleId) {
13871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1388c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStscTableEntries->add(htonl(chunkId));
1389c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStscTableEntries->add(htonl(sampleId));
1390c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStscTableEntries->add(htonl(1));
13911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
13921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
13931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
1394c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStssTableEntries->add(htonl(sampleId));
13951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
13961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
13971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry(
139879761ab096f57c3027fad9556c2bc436672d614eJames Dong        size_t sampleCount, int32_t duration) {
13991f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
14005a217fba010e801c255503602bda4b86ac5a6ac9James Dong    if (duration == 0) {
14015ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("0-duration samples found: %d", sampleCount);
14025a217fba010e801c255503602bda4b86ac5a6ac9James Dong    }
1403c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->add(htonl(sampleCount));
1404c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->add(htonl(duration));
14051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
14061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1407965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::addOneCttsTableEntry(
1408965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        size_t sampleCount, int32_t duration) {
1409965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
1410965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    if (mIsAudio) {
1411965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
1412965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
1413c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->add(htonl(sampleCount));
1414c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->add(htonl(duration));
1415965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong}
1416965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
1417c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) {
1418c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mOwner->use32BitFileOffset()) {
1419c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        uint32_t value = offset;
1420c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStcoTableEntries->add(htonl(value));
1421c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    } else {
1422c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mCo64TableEntries->add(hton64(offset));
1423c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    }
14241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
14251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1426c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() {
14273856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("setTimeScale");
1428c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Default time scale
1429c059860c73678a202bfa33062723e8f82fb779d9James Dong    mTimeScale = 90000;
1430c059860c73678a202bfa33062723e8f82fb779d9James Dong
1431c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mIsAudio) {
1432c059860c73678a202bfa33062723e8f82fb779d9James Dong        // Use the sampling rate as the default time scale for audio track.
1433c059860c73678a202bfa33062723e8f82fb779d9James Dong        int32_t sampleRate;
1434c059860c73678a202bfa33062723e8f82fb779d9James Dong        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1435c059860c73678a202bfa33062723e8f82fb779d9James Dong        CHECK(success);
1436c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = sampleRate;
1437c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1438c059860c73678a202bfa33062723e8f82fb779d9James Dong
1439c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If someone would like to overwrite the timescale, use user-supplied value.
1440c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t timeScale;
1441c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1442c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = timeScale;
1443c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1444c059860c73678a202bfa33062723e8f82fb779d9James Dong
144543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mTimeScale, 0);
144619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber}
144719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
144819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
144919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    const char *mime;
145019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
145119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
145219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
145319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
145419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
145519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
145619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
145719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificData = malloc(size);
145819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificDataSize = size;
145919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            memcpy(mCodecSpecificData, data, size);
146019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mGotAllCodecSpecificData = true;
146119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
146219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
146319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
146419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
146519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
146619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
146719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
146819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            ESDS esds(data, size);
146919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
147019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificData = malloc(size);
147119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificDataSize = size;
147219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                memcpy(mCodecSpecificData, data, size);
147319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mGotAllCodecSpecificData = true;
147419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            }
147519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
147619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
147720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
147820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
147920111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
148020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
148120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1482c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStszTableEntries;
1483c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStcoTableEntries;
1484c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mCo64TableEntries;
1485c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStscTableEntries;
1486c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mSttsTableEntries;
1487c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStssTableEntries;
1488c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mCttsTableEntries;
1489c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
1490c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStszTableEntries = NULL;
1491c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStcoTableEntries = NULL;
1492c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCo64TableEntries = NULL;
1493c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStscTableEntries = NULL;
1494c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries = NULL;
1495c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStssTableEntries = NULL;
1496c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries = NULL;
1497c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
149820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
149920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
150020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
150120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
150220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
150320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
150493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
15053856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("initTrackingProgressStatus");
150693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mPreviousTrackTimeUs = -1;
150793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackingProgressStatus = false;
150893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
150993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    {
151093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeUs;
151193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
15123856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("Receive request to track progress status for every %lld us", timeUs);
151393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackEveryTimeDurationUs = timeUs;
151493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackingProgressStatus = true;
151593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
151693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
151793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
151893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
15191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static
15201c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) {
15213856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("ThreadWrapper: %p", me);
15221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
15231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    writer->threadFunc();
15241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return NULL;
15251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15271c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) {
15283856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("bufferChunk: %p", chunk.mTrack);
15291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Mutex::Autolock autolock(mLock);
15301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK_EQ(mDone, false);
15311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
15331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
15341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (chunk.mTrack == it->mTrack) {  // Found owner
15361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            it->mChunks.push_back(chunk);
15371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.signal();
15381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            return;
15391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
15401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
15411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
154243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK(!"Received a chunk for a unknown track");
15431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1545fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) {
15463856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeChunkToFile: %lld from %s track",
15475410afcbb0af5d29d9f710a1c2978c500f9792dcPannag Sanketi        chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video");
1548fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1549fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    int32_t isFirstSample = true;
1550fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    while (!chunk->mSamples.empty()) {
1551fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1552fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1553fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        off64_t offset = chunk->mTrack->isAvc()
1554fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                ? addLengthPrefixedSample_l(*it)
1555fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                : addSample_l(*it);
1556fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1557fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (isFirstSample) {
1558fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            chunk->mTrack->addChunkOffset(offset);
1559fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            isFirstSample = false;
15601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
15611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it)->release();
15631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it) = NULL;
1564fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk->mSamples.erase(it);
15651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1566fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    chunk->mSamples.clear();
15671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1569fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() {
15703856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeAllChunks");
15711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    size_t outstandingChunks = 0;
157270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    Chunk chunk;
157370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    while (findChunkToWrite(&chunk)) {
1574e9f6d0579603372fd2547e6c5ba6e114c6f8cba7James Dong        writeChunkToFile(&chunk);
157570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        ++outstandingChunks;
15761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
157770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
157870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    sendSessionSummary();
157970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
15801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mChunkInfos.clear();
1581b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("%d chunks are written in the last batch", outstandingChunks);
15821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1584fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
15853856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("findChunkToWrite");
15861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
15881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Track *track = NULL;
15891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
15901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
15911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (!it->mChunks.empty()) {
15921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            List<Chunk>::iterator chunkIt = it->mChunks.begin();
15931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (chunkIt->mTimeStampUs < minTimestampUs) {
15941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                minTimestampUs = chunkIt->mTimeStampUs;
15951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                track = it->mTrack;
15961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            }
15971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
15981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
15991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (track == NULL) {
16013856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Nothing to be written after all");
1602fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        return false;
16031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
16041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mIsFirstChunk) {
16061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsFirstChunk = false;
16071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1608fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
16091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
16101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
16111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it->mTrack == track) {
1612fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            *chunk = *(it->mChunks.begin());
1613fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            it->mChunks.erase(it->mChunks.begin());
1614fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            CHECK_EQ(chunk->mTrack, track);
161570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
161670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t interChunkTimeUs =
161770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
161870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
161970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs = interChunkTimeUs;
162070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            }
162170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
1622fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            return true;
16231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
16241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1625fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1626fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    return false;
16271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
16281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16291c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() {
16303856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("threadFunc");
16311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1632a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1633fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1634fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    Mutex::Autolock autoLock(mLock);
16351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mDone) {
1636fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        Chunk chunk;
1637fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        bool chunkFound = false;
1638fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1639fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
16401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.wait(mLock);
16411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
16421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1643fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // Actual write without holding the lock in order to
1644fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // reduce the blocking time for media track threads.
1645fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (chunkFound) {
1646fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.unlock();
1647fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            writeChunkToFile(&chunk);
1648fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.lock();
1649fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        }
16501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1651fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1652fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    writeAllChunks();
16531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
16541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16551c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() {
16563856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("startWriterThread");
16571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mDone = false;
16591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsFirstChunk = true;
1660e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mDriftTimeUs = 0;
16611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<Track *>::iterator it = mTracks.begin();
16621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mTracks.end(); ++it) {
16631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        ChunkInfo info;
16641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        info.mTrack = *it;
166570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mPrevChunkTimestampUs = 0;
166670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mMaxInterChunkDurUs = 0;
16671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.push_back(info);
16681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
16691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_t attr;
16711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_init(&attr);
16721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
16731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_create(&mThread, &attr, ThreadWrapper, this);
16741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_destroy(&attr);
1675411ba422e3635d534928ffd81abf54f4f291c739James Dong    mWriterThreadStarted = true;
16761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
16771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
16781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
168093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) {
1681a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (!mDone && mPaused) {
1682a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mPaused = false;
1683a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mResumed = true;
1684a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
1685a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
168625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
168793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t startTimeUs;
168819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
168919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        startTimeUs = 0;
169019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
169170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    mStartTimeRealUs = startTimeUs;
169219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
169313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t rotationDegrees;
169413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
169513f6284305e4b27395a23db7882d670bdb1bcae1James Dong        mRotation = rotationDegrees;
169613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
169713f6284305e4b27395a23db7882d670bdb1bcae1James Dong
16985b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong    mIsRealTimeRecording = true;
1699e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    {
1700e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        int32_t isNotRealTime;
1701e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
1702e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            mIsRealTimeRecording = (isNotRealTime == 0);
1703e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1704e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    }
1705e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
170693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    initTrackingProgressStatus(params);
170793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1708f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    sp<MetaData> meta = new MetaData;
1709a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mIsRealTimeRecording && mOwner->numTracks() > 1) {
1710a472613aec322e25891abf5c77bf3f7e3c244920James Dong        /*
1711a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * This extra delay of accepting incoming audio/video signals
1712a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * helps to align a/v start time at the beginning of a recording
1713a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * session, and it also helps eliminate the "recording" sound for
1714a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * camcorder applications.
1715a472613aec322e25891abf5c77bf3f7e3c244920James Dong         *
171686b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * If client does not set the start time offset, we fall back to
171786b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * use the default initial delay value.
1718a472613aec322e25891abf5c77bf3f7e3c244920James Dong         */
171986b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
172086b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
172186b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
172286b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
172386b7f47aa7482424cf8fd248f1315311919be3b0James Dong        startTimeUs += startTimeOffsetUs;
1724df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Start time offset: %lld us", startTimeOffsetUs);
1725a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
1726a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1727f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    meta->setInt64(kKeyTime, startTimeUs);
1728a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1729f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    status_t err = mSource->start(meta.get());
173025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
173125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
173225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
173325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
173420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
173520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
173620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
173720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
173820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
173920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
1740eaae38445a340c4857c1c5569475879a728e63b7James Dong    mStarted = true;
1741c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs = 0;
174225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
1743956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    mEstimatedTrackSizeBytes = 0;
17441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mMdatSizeBytes = 0;
174543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mMaxChunkDurationUs = 0;
174620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
174725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
174820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
174925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
175025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
175120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
175220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
175337187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() {
1754a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
175537187916a486504acaf83bea30147eb5fbf46ae5James Dong    return OK;
1756a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1757a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
175837187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() {
1759b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1760eaae38445a340c4857c1c5569475879a728e63b7James Dong    if (!mStarted) {
176129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Stop() called but track is not started");
1762eaae38445a340c4857c1c5569475879a728e63b7James Dong        return ERROR_END_OF_STREAM;
1763eaae38445a340c4857c1c5569475879a728e63b7James Dong    }
1764eaae38445a340c4857c1c5569475879a728e63b7James Dong
176520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
176637187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
176720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
176820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
176920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
177020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
177120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
177220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
177337187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = (status_t) dummy;
177437187916a486504acaf83bea30147eb5fbf46ae5James Dong
1775b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
177637187916a486504acaf83bea30147eb5fbf46ae5James Dong    {
177737187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = mSource->stop();
177837187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
177937187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
178037187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
178137187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
178237187916a486504acaf83bea30147eb5fbf46ae5James Dong
1783b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
178437187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
178520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
178620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
178725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
178825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
178925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
179025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
179120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
179220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
179320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
179420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
179537187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = track->threadEntry();
179637187916a486504acaf83bea30147eb5fbf46ae5James Dong    return (void *) err;
179720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
179820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
17993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) {
18003856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("getNalUnitType: %d", byte);
18013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // nal_unit_type: 5-bit unsigned integer
18033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *type = (byte & 0x1F);
18043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode(
18073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length) {
18083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18093856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("findNextStartCode: %p %d", data, length);
18103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = length;
18123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4  &&
18133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
18143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        --bytesLeft;
18153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (bytesLeft <= 4) {
18173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft = 0; // Last parameter set
18183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return &data[length - bytesLeft];
18203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet(
18233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
18243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18253856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("parseParamSet");
18263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    CHECK(type == kNalUnitTypeSeqParamSet ||
18273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong          type == kNalUnitTypePicParamSet);
18283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = findNextStartCode(data, length);
18303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *paramSetLen = nextStartCode - data;
18313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (*paramSetLen == 0) {
183229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Param set is malformed, since its length is 0");
18333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return NULL;
18343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    AVCParamSet paramSet(*paramSetLen, data);
18373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (type == kNalUnitTypeSeqParamSet) {
18383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (*paramSetLen < 4) {
183929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Seq parameter set malformed");
18403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return NULL;
18413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
18423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mSeqParamSets.empty()) {
18433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc = data[1];
18443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileCompatible = data[2];
18453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mLevelIdc = data[3];
18463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
18473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (mProfileIdc != data[1] ||
18483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mProfileCompatible != data[2] ||
18493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mLevelIdc != data[3]) {
185029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("Inconsistent profile/level found in seq parameter sets");
18513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return NULL;
18523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
18533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
18543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mSeqParamSets.push_back(paramSet);
18553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    } else {
18563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mPicParamSets.push_back(paramSet);
18573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return nextStartCode;
18593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData(
18623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
18633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("copyAVCCodecSpecificData");
18643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 2 bytes for each of the parameter set length field
18663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // plus the 7 bytes for the header
18673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4 + 7) {
186829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Codec specific data length too short: %d", size);
18693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return ERROR_MALFORMED;
18703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = size;
18733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificData = malloc(size);
18743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    memcpy(mCodecSpecificData, data, size);
18753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
18763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData(
18793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
18803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18813856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("parseAVCCodecSpecificData");
18823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data starts with a start code.
18833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // SPS and PPS are separated with start codes.
18843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Also, SPS must come before PPS
18853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t type = kNalUnitTypeSeqParamSet;
18863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotSps = false;
18873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotPps = false;
18883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *tmp = data;
18893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = data;
18903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = size;
18913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t paramSetLen = 0;
18923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = 0;
18933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
18943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        getNalUnitType(*(tmp + 4), &type);
18953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (type == kNalUnitTypeSeqParamSet) {
18963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (gotPps) {
189729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("SPS must come before PPS");
18983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
18993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
19013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotSps = true;
19023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
19043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else if (type == kNalUnitTypePicParamSet) {
19053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
190629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("SPS must come before PPS");
19073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
19083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotPps) {
19103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotPps = true;
19113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
19133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
191429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Only SPS and PPS Nal units are expected");
19153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nextStartCode == NULL) {
19193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Move on to find the next parameter set
19233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft -= nextStartCode - tmp;
19243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        tmp = nextStartCode;
19253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mCodecSpecificDataSize += (2 + paramSetLen);
19263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
19293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of seq parameter sets
19303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nSeqParamSets = mSeqParamSets.size();
19313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets == 0) {
193229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Cound not find sequence parameter set");
19333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets > 0x1F) {
193729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
19383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
19433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of pic parameter sets
19443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nPicParamSets = mPicParamSets.size();
19453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets == 0) {
194629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Cound not find picture parameter set");
19473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets > 0xFF) {
195029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Too many pic parameter sets (%d) found", nPicParamSets);
19513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19541374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// FIXME:
19551374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
19561374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// and remove #if 0
19571374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#if 0
19583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
19593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the profiles
19603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // These profiles requires additional parameter set extensions
19613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mProfileIdc == 100 || mProfileIdc == 110 ||
19623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc == 122 || mProfileIdc == 144) {
196329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
19643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return BAD_VALUE;
19653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19671374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#endif
19683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
19693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
1970548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
197103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
197203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
1973548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
197403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
197529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Already have codec specific data");
197603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
197703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
197803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4) {
198029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Codec specific data length too short: %d", size);
198103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
198203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
198303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data is in the form of AVCCodecSpecificData
19853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (memcmp("\x00\x00\x00\x01", data, 4)) {
19863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return copyAVCCodecSpecificData(data, size);
198703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
198803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (parseAVCCodecSpecificData(data, size) != OK) {
199003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
199103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
199203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // ISO 14496-15: AVC file format
19943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
199503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
199603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
19973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = 1;                     // version
19983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[1] = mProfileIdc;           // profile indication
19993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[2] = mProfileCompatible;    // profile compatibility
20003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[3] = mLevelIdc;
200103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
2003b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mOwner->useNalLengthFour()) {
2004b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 3;  // length size == 4 bytes
2005b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
2006b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 1;  // length size == 2 bytes
2007b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
200803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 3-bit '111' followed by 5-bit numSequenceParameterSets
20103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nSequenceParamSets = mSeqParamSets.size();
20113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[5] = 0xe0 | nSequenceParamSets;
20123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 6;
20133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
20143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mSeqParamSets.end(); ++it) {
20153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit sequence parameter set length
20163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t seqParamSetLength = it->mLength;
20173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = seqParamSetLength >> 8;
20183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = seqParamSetLength & 0xff;
20193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
20203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // SPS NAL unit (sequence parameter length bytes)
20213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, seqParamSetLength);
20223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + seqParamSetLength);
20233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
20243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
20253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 8-bit nPictureParameterSets
20263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nPictureParamSets = mPicParamSets.size();
20273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = nPictureParamSets;
20283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 1;
20293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
20303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mPicParamSets.end(); ++it) {
20313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit picture parameter set length
20323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t picParamSetLength = it->mLength;
20333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = picParamSetLength >> 8;
20343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = picParamSetLength & 0xff;
20353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
20363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // PPS Nal unit (picture parameter set length bytes)
20373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, picParamSetLength);
20383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + picParamSetLength);
20393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
204003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
204103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
204203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
204303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
2044872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
2045872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that
2046872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information
2047872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio
2048872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger
2049872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
2050872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined.
2051872a481558350634a3fd5cb67939de288af00ecbJames Dong */
2052872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
2053872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t driftTimeUs = 0;
2054872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
2055872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
2056872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
2057872a481558350634a3fd5cb67939de288af00ecbJames Dong        mOwner->setDriftTimeUs(timeUs);
2058872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2059872a481558350634a3fd5cb67939de288af00ecbJames Dong}
2060872a481558350634a3fd5cb67939de288af00ecbJames Dong
206137187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() {
206230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
206313aec890216948b0c364f8f92792129d0335f506James Dong    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
206443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
206513aec890216948b0c364f8f92792129d0335f506James Dong    int64_t chunkTimestampUs = 0;
206613aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nChunks = 0;
206713aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nZeroLengthFrames = 0;
2068965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastTimestampUs = 0;      // Previous sample time stamp
2069965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastDurationUs = 0;       // Between the previous two samples
2070965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t currDurationTicks = 0;    // Timescale based ticks
2071965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastDurationTicks = 0;    // Timescale based ticks
2072965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int32_t sampleCount = 1;          // Sample count in the current stts table entry
2073000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    uint32_t previousSampleSize = 0;  // Size of the previous sample
2074a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    int64_t previousPausedDurationUs = 0;
2075965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t timestampUs = 0;
2076000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t cttsOffsetTimeUs = 0;
2077000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
2078000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
207943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
2080c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t lastSamplesPerChunk = 0;
2081e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2082a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    if (mIsAudio) {
2083a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
2084a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    } else {
2085a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
2086a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    }
208786106f8b0641444c97a39e9788eeef55ab2a2ac6Glenn Kasten    androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
2088985f838934510983d8a887461e98dca60a6e858fJames Dong
2089d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong    sp<MetaData> meta_data;
209020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
209193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t err = OK;
209220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
209393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    while (!mDone && (err = mSource->read(&buffer)) == OK) {
209420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
209520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
209620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
209713aec890216948b0c364f8f92792129d0335f506James Dong            ++nZeroLengthFrames;
209820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
209920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
210020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2101a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // If the codec specific data has not been received yet, delay pause.
2102a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // After the codec specific data is received, discard what we received
2103a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // when the track is to be paused.
2104a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused && !mResumed) {
2105a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer->release();
2106a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer = NULL;
2107a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            continue;
2108a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
2109a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
211030ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
211130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
211203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
211303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
211403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
2115548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            CHECK(!mGotAllCodecSpecificData);
2116548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
21171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAvc) {
211803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
211903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
212003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
212103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
212243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                CHECK_EQ((status_t)OK, err);
21231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            } else if (mIsMPEG4) {
212403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
212503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
212603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
212703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
212803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
212903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
213030ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
213130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
213230ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
213330ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
213430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
2135548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            mGotAllCodecSpecificData = true;
213630ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
2137a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
2138a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
2139d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // Make a deep copy of the MediaBuffer and Metadata and release
2140d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // the original as soon as we can
2141d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
2142d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
2143d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                buffer->range_length());
2144d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        copy->set_range(0, buffer->range_length());
2145d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data = new MetaData(*buffer->meta_data().get());
2146d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer->release();
2147d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer = NULL;
2148d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
21491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAvc) StripStartcode(copy);
2150e136c3bb38e88315bf8797a464ebf2c788296b22James Dong
2151b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        size_t sampleSize = copy->range_length();
2152b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        if (mIsAvc) {
2153b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            if (mOwner->useNalLengthFour()) {
2154b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 4;
2155b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            } else {
2156b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 2;
2157b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            }
2158b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        }
2159050b28a593350047845a45a14cc5026221ac1620James Dong
2160d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        // Max file size or duration handling
21611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mMdatSizeBytes += sampleSize;
21621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        updateTrackSizeEstimate();
21631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
2164d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileSizeLimit()) {
2165d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
2166d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
2167d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
2168d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileDurationLimit()) {
2169d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
2170d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
2171d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
2172d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2173050b28a593350047845a45a14cc5026221ac1620James Dong
2174d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        int32_t isSync = false;
2175d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
2176d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
2177d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
2178d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong////////////////////////////////////////////////////////////////////////////////
2179c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        if (mStszTableEntries->count() == 0) {
218070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mFirstSampleTimeRealUs = systemTime() / 1000;
2181f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimestampUs = timestampUs;
2182f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mOwner->setStartTimestampUs(mStartTimestampUs);
21838428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs = mStartTimestampUs;
21843c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        }
218548c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
2186a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mResumed) {
21878428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
218843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
21898428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
219043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(pausedDurationUs, lastDurationUs);
21918428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
2192a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mResumed = false;
2193a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
2194a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
2195a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        timestampUs -= previousPausedDurationUs;
219643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GE(timestampUs, 0ll);
2197000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        if (!mIsAudio) {
2198965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            /*
2199965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             * Composition time: timestampUs
2200965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             * Decoding time: decodingTimeUs
2201000e18370baae60ffd9f25b509501dd8c26deabfJames Dong             * Composition time offset = composition time - decoding time
2202965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             */
2203965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            int64_t decodingTimeUs;
2204965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
2205965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            decodingTimeUs -= previousPausedDurationUs;
2206000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            cttsOffsetTimeUs =
2207000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
220843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(cttsOffsetTimeUs, 0ll);
2209965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            timestampUs = decodingTimeUs;
2210000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            ALOGV("decoding time: %lld and ctts offset time: %lld",
2211000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                timestampUs, cttsOffsetTimeUs);
2212000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2213000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            // Update ctts box table if necessary
2214000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            currCttsOffsetTimeTicks =
2215000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
221643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
2217c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() == 0) {
221843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // Force the first ctts table entry to have one single entry
221943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // so that we can do adjustment for the initial track start
222043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // time offset easily in writeCttsBox().
222143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
222243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
222343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                cttsSampleCount = 0;      // No sample in ctts box is pending
222443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            } else {
222543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
222643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
222743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
222843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    cttsSampleCount = 1;  // One sample in ctts box is pending
222943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                } else {
223043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    ++cttsSampleCount;
223143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                }
223243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            }
2233000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2234000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            // Update ctts time offset range
2235c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() == 0) {
2236000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2237000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2238000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            } else {
2239000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
2240000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2241000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
2242000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2243000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                }
2244000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            }
2245000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2246965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        }
2247872a481558350634a3fd5cb67939de288af00ecbJames Dong
2248872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mIsRealTimeRecording) {
2249872a481558350634a3fd5cb67939de288af00ecbJames Dong            if (mIsAudio) {
2250872a481558350634a3fd5cb67939de288af00ecbJames Dong                updateDriftTime(meta_data);
2251e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
2252e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
2253872a481558350634a3fd5cb67939de288af00ecbJames Dong
225443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GE(timestampUs, 0ll);
22553856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("%s media time stamp: %lld and previous paused duration %lld",
22568428af5381e835cc783b7ecb0d71cb60961c99c2James Dong                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
2257c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        if (timestampUs > mTrackDurationUs) {
2258c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            mTrackDurationUs = timestampUs;
22593b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
22603b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
22615a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // We need to use the time scale based ticks, rather than the
22625a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // timestamp itself to determine whether we have to use a new
22635a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // stts entry, since we may have rounding errors.
22645a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // The calculation is intended to reduce the accumulated
22655a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // rounding errors.
22665a217fba010e801c255503602bda4b86ac5a6ac9James Dong        currDurationTicks =
22675a217fba010e801c255503602bda4b86ac5a6ac9James Dong            ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
22685a217fba010e801c255503602bda4b86ac5a6ac9James Dong                (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2269c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        if (currDurationTicks < 0ll) {
2270c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            ALOGE("timestampUs %lld < lastTimestampUs %lld for %s track",
2271c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                timestampUs, lastTimestampUs, mIsAudio? "Audio": "Video");
2272c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            return UNKNOWN_ERROR;
22738c460498c028888c533ab442be12b6d4b669b965James Dong        }
22748c460498c028888c533ab442be12b6d4b669b965James Dong
2275c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStszTableEntries->add(htonl(sampleSize));
2276c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        if (mStszTableEntries->count() > 2) {
2277c059860c73678a202bfa33062723e8f82fb779d9James Dong
2278a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // Force the first sample to have its own stts entry so that
2279a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // we can adjust its value later to maintain the A/V sync.
2280c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
228179761ab096f57c3027fad9556c2bc436672d614eJames Dong                addOneSttsTableEntry(sampleCount, lastDurationTicks);
2282be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                sampleCount = 1;
2283be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
2284be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                ++sampleCount;
2285be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
2286965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2287be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2288be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        if (mSamplesHaveSameSize) {
2289c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
2290be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSamplesHaveSameSize = false;
2291be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
22928644c14618d30d9e57a69df40ed939986ebf02c4James Dong            previousSampleSize = sampleSize;
2293be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
22943856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
2295a472613aec322e25891abf5c77bf3f7e3c244920James Dong                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
22968644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastDurationUs = timestampUs - lastTimestampUs;
2297c059860c73678a202bfa33062723e8f82fb779d9James Dong        lastDurationTicks = currDurationTicks;
22988644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastTimestampUs = timestampUs;
229920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2300d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        if (isSync != 0) {
2301c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            addOneStssTableEntry(mStszTableEntries->count());
2302d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        }
2303d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
230493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (mTrackingProgressStatus) {
230593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            if (mPreviousTrackTimeUs <= 0) {
230693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong                mPreviousTrackTimeUs = mStartTimestampUs;
230793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            }
2308faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            trackProgressStatus(timestampUs);
230993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
231043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        if (!hasMultipleTracks) {
2311c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
231258ae9c530247668f8af36e30d228c716c226b3d4James Dong                                 : mOwner->addSample_l(copy);
2313c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
2314c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t count = (mOwner->use32BitFileOffset()
2315c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        ? mStcoTableEntries->count()
2316c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        : mCo64TableEntries->count());
2317c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
2318c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (count == 0) {
23191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addChunkOffset(offset);
232058ae9c530247668f8af36e30d228c716c226b3d4James Dong            }
232158ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy->release();
232258ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy = NULL;
232358ae9c530247668f8af36e30d228c716c226b3d4James Dong            continue;
232458ae9c530247668f8af36e30d228c716c226b3d4James Dong        }
232513aec890216948b0c364f8f92792129d0335f506James Dong
232613aec890216948b0c364f8f92792129d0335f506James Dong        mChunkSamples.push_back(copy);
232713aec890216948b0c364f8f92792129d0335f506James Dong        if (interleaveDurationUs == 0) {
23281f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStscTableEntry(++nChunks, 1);
23291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            bufferChunk(timestampUs);
233013aec890216948b0c364f8f92792129d0335f506James Dong        } else {
233113aec890216948b0c364f8f92792129d0335f506James Dong            if (chunkTimestampUs == 0) {
233213aec890216948b0c364f8f92792129d0335f506James Dong                chunkTimestampUs = timestampUs;
233313aec890216948b0c364f8f92792129d0335f506James Dong            } else {
233443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
233543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                if (chunkDurationUs > interleaveDurationUs) {
233643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    if (chunkDurationUs > mMaxChunkDurationUs) {
233743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                        mMaxChunkDurationUs = chunkDurationUs;
233843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    }
233913aec890216948b0c364f8f92792129d0335f506James Dong                    ++nChunks;
234013aec890216948b0c364f8f92792129d0335f506James Dong                    if (nChunks == 1 ||  // First chunk
2341c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        lastSamplesPerChunk != mChunkSamples.size()) {
2342c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        lastSamplesPerChunk = mChunkSamples.size();
2343c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        addOneStscTableEntry(nChunks, lastSamplesPerChunk);
234413aec890216948b0c364f8f92792129d0335f506James Dong                    }
23451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                    bufferChunk(timestampUs);
234613aec890216948b0c364f8f92792129d0335f506James Dong                    chunkTimestampUs = timestampUs;
234713aec890216948b0c364f8f92792129d0335f506James Dong                }
234813aec890216948b0c364f8f92792129d0335f506James Dong            }
234913aec890216948b0c364f8f92792129d0335f506James Dong        }
235013aec890216948b0c364f8f92792129d0335f506James Dong
235120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
235225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
235345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (isTrackMalFormed()) {
2354690f546b0ee548dbfe997df36418e5302ec2d786James Dong        err = ERROR_MALFORMED;
2355f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong    }
235645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
2357bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    mOwner->trackProgressStatus(mTrackId, -1, err);
2358be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
235913aec890216948b0c364f8f92792129d0335f506James Dong    // Last chunk
236043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (!hasMultipleTracks) {
2361c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        addOneStscTableEntry(1, mStszTableEntries->count());
236258ae9c530247668f8af36e30d228c716c226b3d4James Dong    } else if (!mChunkSamples.empty()) {
23631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(++nChunks, mChunkSamples.size());
23641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        bufferChunk(timestampUs);
236513aec890216948b0c364f8f92792129d0335f506James Dong    }
236613aec890216948b0c364f8f92792129d0335f506James Dong
2367be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // We don't really know how long the last frame lasts, since
2368be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // there is no frame time after it, just repeat the previous
2369be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // frame's duration.
2370c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mStszTableEntries->count() == 1) {
23718f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        lastDurationUs = 0;  // A single sample's duration
237279761ab096f57c3027fad9556c2bc436672d614eJames Dong        lastDurationTicks = 0;
2373be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    } else {
2374be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        ++sampleCount;  // Count for the last sample
2375be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    }
2376a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2377c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mStszTableEntries->count() <= 2) {
237879761ab096f57c3027fad9556c2bc436672d614eJames Dong        addOneSttsTableEntry(1, lastDurationTicks);
2379a472613aec322e25891abf5c77bf3f7e3c244920James Dong        if (sampleCount - 1 > 0) {
238079761ab096f57c3027fad9556c2bc436672d614eJames Dong            addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
2381a472613aec322e25891abf5c77bf3f7e3c244920James Dong        }
2382a472613aec322e25891abf5c77bf3f7e3c244920James Dong    } else {
238379761ab096f57c3027fad9556c2bc436672d614eJames Dong        addOneSttsTableEntry(sampleCount, lastDurationTicks);
2384a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
2385a472613aec322e25891abf5c77bf3f7e3c244920James Dong
238643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    // The last ctts box may not have been written yet, and this
238743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    // is to make sure that we write out the last ctts box.
238843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
238943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        if (cttsSampleCount > 0) {
239043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
239143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        }
239243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    }
239343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong
2394c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs += lastDurationUs;
239525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
239643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
239743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    sendTrackSummary(hasMultipleTracks);
239843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2399df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
2400c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            count, nZeroLengthFrames, mStszTableEntries->count(), mIsAudio? "audio": "video");
2401872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsAudio) {
2402df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2403872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2404365a963142093a1cd8efdcea76b5f65096a5b115James Dong
240537187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err == ERROR_END_OF_STREAM) {
240637187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
240737187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
240837187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
2409365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
2410365a963142093a1cd8efdcea76b5f65096a5b115James Dong
241145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dongbool MPEG4Writer::Track::isTrackMalFormed() const {
2412c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mStszTableEntries->count() == 0) {                      // no samples written
241329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("The number of recorded samples is 0");
241445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
241545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
241645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
2417c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (!mIsAudio && mStssTableEntries->count() == 0) {  // no sync frames for video
241829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("There are no sync frames for video track");
241945c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
242045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
242145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
242245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (OK != checkCodecSpecificData()) {         // no codec specific data
242345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
242445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
242545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
242645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    return false;
242745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong}
242845c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
242943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
243007ec01904613a0bac32caaa8444b4690998faed7James Dong
243107ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send track summary only if test mode is enabled.
243207ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
243307ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
243407ec01904613a0bac32caaa8444b4690998faed7James Dong    }
243507ec01904613a0bac32caaa8444b4690998faed7James Dong
243643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int trackNum = (mTrackId << 28);
243743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
243843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
243943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
244043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mIsAudio? 0: 1);
244143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
244243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
244343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
244443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mTrackDurationUs / 1000);
244543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
244643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
244743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
2448c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                    mStszTableEntries->count());
244943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
245086b7f47aa7482424cf8fd248f1315311919be3b0James Dong    {
245186b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // The system delay time excluding the requested initial delay that
245286b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // is used to eliminate the recording sound.
245386b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
245486b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
245586b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
245686b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
245786b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t initialDelayUs =
245886b7f47aa7482424cf8fd248f1315311919be3b0James Dong            mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
245986b7f47aa7482424cf8fd248f1315311919be3b0James Dong
246086b7f47aa7482424cf8fd248f1315311919be3b0James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
246170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
246270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    (initialDelayUs) / 1000);
246386b7f47aa7482424cf8fd248f1315311919be3b0James Dong    }
246470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
246507ec01904613a0bac32caaa8444b4690998faed7James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
246607ec01904613a0bac32caaa8444b4690998faed7James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
246707ec01904613a0bac32caaa8444b4690998faed7James Dong                    mMdatSizeBytes / 1024);
246807ec01904613a0bac32caaa8444b4690998faed7James Dong
246943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (hasMultipleTracks) {
247043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
247143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
247243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mMaxChunkDurationUs / 1000);
247370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
247470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
247570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mStartTimestampUs != moovStartTimeUs) {
247670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
247770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
247870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
247970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    startTimeOffsetUs / 1000);
248070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        }
248143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    }
248243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong}
248343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2484faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
24853856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("trackProgressStatus: %lld us", timeUs);
2486c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
2487215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    if (mTrackEveryTimeDurationUs > 0 &&
2488215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
24893856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Fire time tracking progress status at %lld us", timeUs);
2490bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
249193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        mPreviousTrackTimeUs = timeUs;
249293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
249393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
249493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
2495faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus(
2496bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        size_t trackId, int64_t timeUs, status_t err) {
2497faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    Mutex::Autolock lock(mLock);
2498bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t trackNum = (trackId << 28);
2499faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2500faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Error notification
2501faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Do not consider ERROR_END_OF_STREAM an error
2502faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (err != OK && err != ERROR_END_OF_STREAM) {
2503bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2504bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2505faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2506faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
2507faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2508faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2509faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (timeUs == -1) {
2510faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send completion notification
2511bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2512bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2513faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2514faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    } else {
2515faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send progress status
2516bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2517bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2518faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               timeUs / 1000);
2519faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2520faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong}
2521faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2522d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
25233856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("setDriftTimeUs: %lld us", driftTimeUs);
2524e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2525d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    mDriftTimeUs = driftTimeUs;
2526e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2527e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2528e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() {
25293856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2530e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2531e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    return mDriftTimeUs;
2532e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2533e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2534b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() {
2535b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    return mUse4ByteNalLength;
2536b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong}
2537b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
25381c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
25393856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("bufferChunk");
25401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
25411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Chunk chunk(this, timestampUs, mChunkSamples);
25421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mOwner->bufferChunk(chunk);
254313aec890216948b0c364f8f92792129d0335f506James Dong    mChunkSamples.clear();
254420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
254520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25463b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
2547c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    return mTrackDurationUs;
254820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
254920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2550d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2551d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return mEstimatedTrackSizeBytes;
2552d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
2553d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2554690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const {
2555690f546b0ee548dbfe997df36418e5302ec2d786James Dong    const char *mime;
2556690f546b0ee548dbfe997df36418e5302ec2d786James Dong    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2557690f546b0ee548dbfe997df36418e5302ec2d786James Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2558690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2559690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2560690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (!mCodecSpecificData ||
2561690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize <= 0) {
256229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Missing codec specific data");
2563690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2564690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2565690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else {
2566690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (mCodecSpecificData ||
2567690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize > 0) {
256829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Unexepected codec specific data found");
2569690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2570690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2571690f546b0ee548dbfe997df36418e5302ec2d786James Dong    }
2572690f546b0ee548dbfe997df36418e5302ec2d786James Dong    return OK;
2573690f546b0ee548dbfe997df36418e5302ec2d786James Dong}
2574690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2575b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
257620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25773856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("%s track time scale: %d",
25781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsAudio? "Audio": "Video", mTimeScale);
25798f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
2580efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    uint32_t now = getMpeg4Time();
2581b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("trak");
2582b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeTkhdBox(now);
2583b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mdia");
2584b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeMdhdBox(now);
2585b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeHdlrBox();
2586b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->beginBox("minf");
2587b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                if (mIsAudio) {
2588b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeSmhdBox();
2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                } else {
2590b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeVmhdBox();
2591b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                }
2592b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeDinfBox();
2593b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeStblBox(use32BitOffset);
2594b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->endBox();  // minf
2595b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->endBox();  // mdia
2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // trak
2597b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stbl");
2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsd");
2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);               // version=0, flags=0
2603b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);               // entry count
2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAudioFourCCBox();
2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeVideoFourCCBox();
2608b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsd
2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeSttsBox();
2611965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    writeCttsBox();
2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mIsAudio) {
2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeStssBox();
2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStszBox();
2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStscBox();
2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStcoBox(use32BitOffset);
2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stbl
2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2620b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() {
2622b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2623b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2625b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mp4v");
2627b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("s263");
2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("avc1");
2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
263229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Unknown mime type '%s'.", mime);
2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2638b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // data ref index
2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2640b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t width, height;
2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeyWidth, &width);
2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = success && mMeta->findInt32(kKeyHeight, &height);
2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(width);
2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(height);
2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // horiz resolution
2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // vert resolution
2654b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // frame count
2656c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo    mOwner->writeInt8(0);            // compressor string length
2657c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo    mOwner->write("                               ", 31);
2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x18);        // depth
2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(-1);          // predefined
2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
266143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_LT(23 + mCodecSpecificDataSize, 128);
2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4vEsdsBox();
2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeD263Box();
2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAvccBox();
2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2670b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2671b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writePaspBox();
2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // mp4v, s263 or avc1
2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2675b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() {
2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2677b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *fourcc = NULL;
2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "samr";
2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "sawb";
2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "mp4a";
2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
268729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Unknown mime type '%s'.", mime);
2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(fourcc);        // audio format
2692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x1);         // data ref index
2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t nChannels;
2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(nChannels);   // channel count
2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(16);          // sample size
2701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t samplerate;
2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(samplerate << 16);
2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4aEsdsBox();
2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeDamrBox();
2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() {
2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
272043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mCodecSpecificDataSize, 0);
2721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Make sure all sizes encode to a single byte.
272343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_LT(mCodecSpecificDataSize + 23, 128);
2724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);     // version=0, flags=0
2726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);   // ES_DescrTag
2727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);// ES_ID
2729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);
2730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x15);   // streamType AudioStream
2735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x03);  // XXX
2737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);   // buffer size 24-bit
2738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // max bit rate
2739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // avg bit rate
2740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() {
2756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
275743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mCodecSpecificDataSize, 0);
2758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);    // version=0, flags=0
2761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);  // ES_DescrTag
2763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);  // ES_ID
2765b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x1f);
2766b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2767b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2768b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2769b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2770b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x11);  // streamType VisualStream
2771b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2772b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData[] = {
2773b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01, 0x77, 0x00,
2774b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00,
2775b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00
2776b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2777b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData, sizeof(kData));
2778b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2779b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2780b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2781b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2782b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2783b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2784b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2785b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2786b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2787b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2788b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2789b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2790b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2791b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2792b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2793b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2794efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeTkhdBox(uint32_t now) {
2795b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("tkhd");
2796b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Flags = 7 to indicate that the track is enabled, and
2797b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // part of the presentation
2798b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x07);          // version=0, flags=7
2799b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2800b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2801219f195159f93d627af2b243732e3f9020511a46James Dong    mOwner->writeInt32(mTrackId);      // track id starts with 1
2802b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
28038f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t trakDurationUs = getDurationUs();
2804b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mvhdTimeScale = mOwner->getTimeScale();
2805b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t tkhdDuration =
2806b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2807b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2808b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2809b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2810b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // layer
2811b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // alternate group
2812b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2813b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // reserved
2814b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2815b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCompositionMatrix(mRotation);       // matrix
281620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2817b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2818b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2819b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2820b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2821b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t width, height;
2822b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        bool success = mMeta->findInt32(kKeyWidth, &width);
2823b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        success = success && mMeta->findInt32(kKeyHeight, &height);
2824b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(success);
2825b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2826b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2827b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2828b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2829b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // tkhd
2830b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2831b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2832b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() {
2833b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("vmhd");
2834b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x01);        // version=0, flags=1
2835b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // graphics mode
2836b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // opcolor
2837b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2838b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2839b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2840b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2841b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2842b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() {
2843b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("smhd");
2844b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // version=0, flags=0
2845b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // balance
2846b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2847b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2848b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2849b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2850b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() {
2851b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("hdlr");
2852b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2853b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // component type: should be mhlr
2854b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2855b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2856b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2857b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2858b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Removing "r" for the name string just makes the string 4 byte aligned
2859b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2860b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2861b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2862b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2863efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
2864b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t trakDurationUs = getDurationUs();
2865b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("mdhd");
2866b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2867b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2868b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2869b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mTimeScale);    // media timescale
2870b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2871b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mdhdDuration);  // use media timescale
2872b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Language follows the three letter standard ISO-639-2/T
2873b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 'e', 'n', 'g' for "English", for instance.
2874b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Each character is packed as the difference between its ASCII value and 0x60.
2875b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // For "English", these are 00101, 01110, 00111.
2876b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // XXX: Where is the padding bit located: 0x15C7?
2877b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // language code
2878b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // predefined
2879b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2880b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2881b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2882b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() {
2883b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 3gpp2 Spec AMRSampleEntry fields
2884b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("damr");
2885b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString("   ");  // vendor: 4 bytes
2886b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // decoder version
2887b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2888b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // mode change period
2889b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(1);         // frames per sample
2890b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2891b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2892b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2893b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() {
2894b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // The table index here refers to the sample description index
2895b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // in the sample table entries.
2896b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("url ");
2897b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2898b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // url
2899b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2900b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2901b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() {
2902b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dref");
2903b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2904b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // entry count (either url or urn)
2905b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeUrlBox();
2906b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dref
2907b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2908b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2909b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() {
2910b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dinf");
2911b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeDrefBox();
2912b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dinf
2913b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2914b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2915b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() {
2916b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
291743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(mCodecSpecificDataSize, 5);
2918b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2919b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Patch avcc's lengthSize field to match the number
2920b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // of bytes we use to indicate the size of a nal unit.
2921b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2922b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
2923b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("avcC");
2924b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2925b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // avcC
2926b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2927b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2928b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() {
2929b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("d263");
2930b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // vendor
2931b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // decoder version
2932b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(10);  // level: 10
2933b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // profile: 0
2934b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // d263
2935b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2936b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2937b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square
2938b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() {
2939b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("pasp");
2940b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // hspacing
2941b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // vspacing
2942b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // pasp
2943b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2944b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2945000e18370baae60ffd9f25b509501dd8c26deabfJames Dongint32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
2946a472613aec322e25891abf5c77bf3f7e3c244920James Dong    int64_t trackStartTimeOffsetUs = 0;
2947b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2948b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mStartTimestampUs != moovStartTimeUs) {
294943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GT(mStartTimestampUs, moovStartTimeUs);
2950b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2951b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2952000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
2953000e18370baae60ffd9f25b509501dd8c26deabfJames Dong}
2954000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2955000e18370baae60ffd9f25b509501dd8c26deabfJames Dongvoid MPEG4Writer::Track::writeSttsBox() {
2956000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->beginBox("stts");
2957000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2958c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t duration;
2959c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    CHECK(mSttsTableEntries->get(duration, 1));
2960c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    duration = htonl(duration);  // Back to host byte order
2961c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
2962c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->write(mOwner);
2963b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stts
2964b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
296520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2966965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::writeCttsBox() {
2967965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    if (mIsAudio) {  // ctts is not for audio
2968965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
2969965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
2970965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2971000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    // There is no B frame at all
2972000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
2973000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        return;
2974000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    }
2975000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2976965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    // Do not write ctts box when there is no need to have it.
2977c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mCttsTableEntries->count() == 0) {
2978965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
2979965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
2980965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2981c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ALOGV("ctts box has %d entries with range [%lld, %lld]",
2982c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
2983965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2984965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mOwner->beginBox("ctts");
2985000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2986c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t duration;
2987c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    CHECK(mCttsTableEntries->get(duration, 1));
2988c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    duration = htonl(duration);  // Back host byte order
2989c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1);
2990c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->write(mOwner);
2991965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mOwner->endBox();  // ctts
2992965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong}
2993965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2994b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() {
2995b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stss");
2996b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2997c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStssTableEntries->write(mOwner);
2998b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stss
2999b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
300025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
3001b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() {
3002b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsz");
3003b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3004c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mOwner->writeInt32(0);
3005c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStszTableEntries->write(mOwner);
3006b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsz
3007b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
300820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3009b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() {
3010b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsc");
3011b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3012c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStscTableEntries->write(mOwner);
3013b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsc
3014b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
301520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3016b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
3017b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(use32BitOffset? "stco": "co64");
3018b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3019c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (use32BitOffset) {
3020c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStcoTableEntries->write(mOwner);
3021c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    } else {
3022c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mCo64TableEntries->write(mOwner);
3023b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
3024b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stco or co64
302520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
302620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
302707b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() {
302807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("udta");
302907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeGeoDataBox();
303007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
303107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
303207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
303307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
303407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
303507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
303607b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() {
303707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("\xA9xyz");
303807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    /*
303907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * For historical reasons, any user data start
304007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * with "\0xA9", must be followed by its assoicated
304107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * language code.
3042432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x0012: text string length
3043432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x15c7: lang (locale) code: en
304407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     */
304507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt32(0x001215c7);
304607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLatitude(mLatitudex10000);
304707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLongitude(mLongitudex10000);
304807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt8(0x2F);
304907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
305007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
305107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
305220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
3053