MPEG4Writer.cpp revision a5750e0dad9e90f2195ce36f2c4457fa04b2b83e
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 2020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h> 21a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn#include <fcntl.h> 22a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn#include <inttypes.h> 2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h> 24a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/prctl.h> 25a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn#include <sys/stat.h> 26a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn#include <sys/types.h> 27a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn#include <unistd.h> 28a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn 29a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn#include <utils/Log.h> 3020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong#include <media/stagefright/foundation/ADebug.h> 3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 3518291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 3603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 3720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 3820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 39d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h> 4007ec01904613a0bac32caaa8444b4690998faed7James Dong#include <cutils/properties.h> 4120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 4319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 4411f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih#define WARN_UNLESS(condition, message, ...) \ 4511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih( (CONDITION(condition)) ? false : ({ \ 4611f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih ALOGW("Condition %s failed " message, #condition, ##__VA_ARGS__); \ 4711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih true; \ 4811f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih})) 4911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 5020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 5120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5277e8ae9967a078770416619e99ddb5b010def312James Dongstatic const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; 531f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachadstatic const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32 541f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad // filesystem file size 551f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad // used by most SD cards 563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 5870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongstatic const int64_t kInitialDelayTimeUs = 700000LL; 595b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong 6020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 6120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 62bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); 638f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 6520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 6737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 6837187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 6925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 7020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 713b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 72d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 73b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeTrackHeader(bool use32BitOffset = true); 741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 78c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong void addChunkOffset(off64_t offset); 7970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int32_t getTrackId() const { return mTrackId; } 80dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong status_t dump(int fd, const Vector<String16>& args) const; 8120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 83000e18370baae60ffd9f25b509501dd8c26deabfJames Dong enum { 84000e18370baae60ffd9f25b509501dd8c26deabfJames Dong kMaxCttsOffsetTimeUs = 1000000LL, // 1 second 858c460498c028888c533ab442be12b6d4b669b965James Dong kSampleArraySize = 1000, 86000e18370baae60ffd9f25b509501dd8c26deabfJames Dong }; 87000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 88c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // A helper class to handle faster write box with table entries 89c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong template<class TYPE> 90c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong struct ListTableEntries { 91c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries(uint32_t elementCapacity, uint32_t entryCapacity) 92c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong : mElementCapacity(elementCapacity), 93c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mEntryCapacity(entryCapacity), 94c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mTotalNumTableEntries(0), 95c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mNumValuesInCurrEntry(0), 96c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCurrTableEntriesElement(NULL) { 97c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_GT(mElementCapacity, 0); 98c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_GT(mEntryCapacity, 0); 99c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 100c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 101c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Free the allocated memory. 102c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ~ListTableEntries() { 103c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong while (!mTableEntryList.empty()) { 104c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong typename List<TYPE *>::iterator it = mTableEntryList.begin(); 105c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete[] (*it); 106c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mTableEntryList.erase(it); 107c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 108c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 109c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 110c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Replace the value at the given position by the given value. 111c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // There must be an existing value at the given position. 112c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg value must be in network byte order 113c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg pos location the value must be in. 114c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong void set(const TYPE& value, uint32_t pos) { 11525f0d7ba1987de61c75f8c68b19de48e0ad9736cJames Dong CHECK_LT(pos, mTotalNumTableEntries * mEntryCapacity); 116c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 117c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong typename List<TYPE *>::iterator it = mTableEntryList.begin(); 118c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity)); 119c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong while (it != mTableEntryList.end() && iterations > 0) { 120c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++it; 121c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong --iterations; 122c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 123c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(it != mTableEntryList.end()); 124c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_EQ(iterations, 0); 125c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 126c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong (*it)[(pos % (mElementCapacity * mEntryCapacity))] = value; 127c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 128c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 129c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Get the value at the given position by the given value. 130c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg value the retrieved value at the position in network byte order. 131c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg pos location the value must be in. 132c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @return true if a value is found. 133c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong bool get(TYPE& value, uint32_t pos) const { 13425f0d7ba1987de61c75f8c68b19de48e0ad9736cJames Dong if (pos >= mTotalNumTableEntries * mEntryCapacity) { 135c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong return false; 136c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 137c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 138c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong typename List<TYPE *>::iterator it = mTableEntryList.begin(); 139c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity)); 140c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong while (it != mTableEntryList.end() && iterations > 0) { 141c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++it; 142c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong --iterations; 143c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 144c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(it != mTableEntryList.end()); 145c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_EQ(iterations, 0); 146c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 147c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong value = (*it)[(pos % (mElementCapacity * mEntryCapacity))]; 148c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong return true; 149c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 150c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 151c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Store a single value. 152c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg value must be in network byte order. 153c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong void add(const TYPE& value) { 154c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_LT(mNumValuesInCurrEntry, mElementCapacity); 155c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t nEntries = mTotalNumTableEntries % mElementCapacity; 156c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t nValues = mNumValuesInCurrEntry % mEntryCapacity; 157c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (nEntries == 0 && nValues == 0) { 158c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCurrTableEntriesElement = new TYPE[mEntryCapacity * mElementCapacity]; 159c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(mCurrTableEntriesElement != NULL); 160c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mTableEntryList.push_back(mCurrTableEntriesElement); 161c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 162c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 163c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t pos = nEntries * mEntryCapacity + nValues; 164c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCurrTableEntriesElement[pos] = value; 165c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 166c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++mNumValuesInCurrEntry; 167c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if ((mNumValuesInCurrEntry % mEntryCapacity) == 0) { 168c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++mTotalNumTableEntries; 169c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mNumValuesInCurrEntry = 0; 170c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 171c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 172c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 173c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Write out the table entries: 174c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // 1. the number of entries goes first 175c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // 2. followed by the values in the table enties in order 176c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg writer the writer to actual write to the storage 177c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong void write(MPEG4Writer *writer) const { 178c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_EQ(mNumValuesInCurrEntry % mEntryCapacity, 0); 179c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t nEntries = mTotalNumTableEntries; 180c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong writer->writeInt32(nEntries); 181c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong for (typename List<TYPE *>::iterator it = mTableEntryList.begin(); 182c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong it != mTableEntryList.end(); ++it) { 183c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_GT(nEntries, 0); 184c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (nEntries >= mElementCapacity) { 185c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong writer->write(*it, sizeof(TYPE) * mEntryCapacity, mElementCapacity); 186c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong nEntries -= mElementCapacity; 187c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } else { 188c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong writer->write(*it, sizeof(TYPE) * mEntryCapacity, nEntries); 189c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong break; 190c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 191c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 192c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 193c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 194c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Return the number of entries in the table. 195c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t count() const { return mTotalNumTableEntries; } 196c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 197c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong private: 198c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mElementCapacity; // # entries in an element 199c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mEntryCapacity; // # of values in each entry 200c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mTotalNumTableEntries; 201c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mNumValuesInCurrEntry; // up to mEntryCapacity 202c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong TYPE *mCurrTableEntriesElement; 203c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mutable List<TYPE *> mTableEntryList; 204c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 205c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries); 206c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong }; 207c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 208c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 209c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 21020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 21120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 212693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 214a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 215a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 216eaae38445a340c4857c1c5569475879a728e63b7James Dong volatile bool mStarted; 2171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 2181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 2191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 220bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t mTrackId; 221c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 22243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t mMaxChunkDurationUs; 223e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 224d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 2251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t mMdatSizeBytes; 2268f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 22720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 22920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 230be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 23113aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 2321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 233c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong bool mSamplesHaveSameSize; 234c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStszTableEntries; 235be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 236c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStcoTableEntries; 237c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<off64_t> *mCo64TableEntries; 238c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStscTableEntries; 239c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStssTableEntries; 240c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mSttsTableEntries; 241c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mCttsTableEntries; 242965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 243000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t mMinCttsOffsetTimeUs; 244000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t mMaxCttsOffsetTimeUs; 245965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 2463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 2473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 2483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 2493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 2503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 2513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 2523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 2533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 2543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 2553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 2563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 2573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 2583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 2593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 26020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 26120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 262548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 26393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 26420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 26525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 2663c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 26770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mStartTimeRealUs; 26870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mFirstSampleTimeRealUs; 26993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 27093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 27125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 272872a481558350634a3fd5cb67939de288af00ecbJames Dong // Update the audio track's drift information. 273872a481558350634a3fd5cb67939de288af00ecbJames Dong void updateDriftTime(const sp<MetaData>& meta); 274872a481558350634a3fd5cb67939de288af00ecbJames Dong 275000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int32_t getStartTimeOffsetScaledTime() const; 276000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 27720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 27837187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 27920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 2813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 2823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 283b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size); 284b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size); 285b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size); 286215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 287215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 288faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 28993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 29003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 29119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 29219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 293c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 294c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 295c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 296c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 297c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 298c059860c73678a202bfa33062723e8f82fb779d9James Dong 299690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 300690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 30113f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t mRotation; 302690f546b0ee548dbfe997df36418e5302ec2d786James Dong 3031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void updateTrackSizeEstimate(); 3041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStscTableEntry(size_t chunkId, size_t sampleId); 3051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStssTableEntry(size_t sampleId); 30679761ab096f57c3027fad9556c2bc436672d614eJames Dong 30779761ab096f57c3027fad9556c2bc436672d614eJames Dong // Duration is time scale based 30879761ab096f57c3027fad9556c2bc436672d614eJames Dong void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur); 309965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur); 31045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 31145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong bool isTrackMalFormed() const; 31243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong void sendTrackSummary(bool hasMultipleTracks); 3131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 314b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Write the boxes 315b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStcoBox(bool use32BitOffset); 316b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStscBox(); 317b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStszBox(); 318b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStssBox(); 319b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSttsBox(); 320965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong void writeCttsBox(); 321b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeD263Box(); 322b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writePaspBox(); 323b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAvccBox(); 324b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeUrlBox(); 325b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDrefBox(); 326b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDinfBox(); 327b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDamrBox(); 328efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson void writeMdhdBox(uint32_t now); 329b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSmhdBox(); 330b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVmhdBox(); 331b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeHdlrBox(); 332efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson void writeTkhdBox(uint32_t now); 333b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4aEsdsBox(); 334b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4vEsdsBox(); 335b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAudioFourCCBox(); 336b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVideoFourCCBox(); 337b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStblBox(bool use32BitOffset); 338b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 33920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 34020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 34120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 34220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 34320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 344674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(-1), 345674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(NO_INIT), 346de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mIsRealTimeRecording(true), 347b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 3481acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 349a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 350a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 351a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 352411ba422e3635d534928ffd81abf54f4f291c739James Dong mWriterThreadStarted(false), 35320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 35413aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 3557837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 35607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mInterleaveDurationUs(1000000), 35707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000(0), 35807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000(0), 35986b7f47aa7482424cf8fd248f1315311919be3b0James Dong mAreGeoTagsAvailable(false), 36086b7f47aa7482424cf8fd248f1315311919be3b0James Dong mStartTimeOffsetMs(-1) { 361674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong 362af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); 363674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mFd >= 0) { 364674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = OK; 365674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong } 36620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 36720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 36830ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 369674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(dup(fd)), 370674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(mFd < 0? NO_INIT: OK), 371de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mIsRealTimeRecording(true), 372b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 3731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 374a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 375a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 376a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 377411ba422e3635d534928ffd81abf54f4f291c739James Dong mWriterThreadStarted(false), 37830ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 37913aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 3807837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 38107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mInterleaveDurationUs(1000000), 38207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000(0), 38307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000(0), 38486b7f47aa7482424cf8fd248f1315311919be3b0James Dong mAreGeoTagsAvailable(false), 38586b7f47aa7482424cf8fd248f1315311919be3b0James Dong mStartTimeOffsetMs(-1) { 38630ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 38730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 38820111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 3898bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dong reset(); 39020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong while (!mTracks.empty()) { 3921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong List<Track *>::iterator it = mTracks.begin(); 39320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 3941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong (*it) = NULL; 3951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mTracks.erase(it); 39620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 39720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 39820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 39920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 400dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 401dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 402dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 403dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 404dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 405dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 406dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 407dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 408dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 409dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 410dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 411dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 412dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 413dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 414dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 415dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 416dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 417dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 41884333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber int fd, const Vector<String16>& /* args */) const { 419dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 420dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 421dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 422dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 423dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 424dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 425dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 426dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 427c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong snprintf(buffer, SIZE, " frames encoded : %d\n", mStszTableEntries->count()); 42813210f3346462a86ce9fe3af72a0c200dba84e27James Dong result.append(buffer); 429377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT snprintf(buffer, SIZE, " duration encoded : %" PRId64 " us\n", mTrackDurationUs); 43013210f3346462a86ce9fe3af72a0c200dba84e27James Dong result.append(buffer); 431dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 432dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 433dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 434dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 4352dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 436bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Mutex::Autolock l(mLock); 437bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong if (mStarted) { 43829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Attempt to add source AFTER recording is started"); 439bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong return UNKNOWN_ERROR; 440bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong } 441acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 442acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // At most 2 tracks can be supported. 443acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong if (mTracks.size() >= 2) { 444a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGE("Too many tracks (%zu) to add", mTracks.size()); 445acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return ERROR_UNSUPPORTED; 446acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 447acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 448acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong CHECK(source.get() != NULL); 449acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 450acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // A track of type other than video or audio is not supported. 451acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong const char *mime; 452acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong source->getFormat()->findCString(kKeyMIMEType, &mime); 453acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong bool isAudio = !strncasecmp(mime, "audio/", 6); 454acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong bool isVideo = !strncasecmp(mime, "video/", 6); 455acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong if (!isAudio && !isVideo) { 456acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong ALOGE("Track (%s) other than video or audio is not supported", 457acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong mime); 458acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return ERROR_UNSUPPORTED; 459acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 460acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 461acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // At this point, we know the track to be added is either 462acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // video or audio. Thus, we only need to check whether it 463acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // is an audio track or not (if it is not, then it must be 464acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // a video track). 465acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 466acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // No more than one video or one audio track is supported. 467acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong for (List<Track*>::iterator it = mTracks.begin(); 468acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong it != mTracks.end(); ++it) { 469acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong if ((*it)->isAudio() == isAudio) { 470acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong ALOGE("%s track already exists", isAudio? "Audio": "Video"); 471acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return ERROR_UNSUPPORTED; 472acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 473acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 474acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 475acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // This is the first track of either audio or video. 476acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // Go ahead to add the track. 477219f195159f93d627af2b243732e3f9020511a46James Dong Track *track = new Track(this, source, 1 + mTracks.size()); 47820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 4792dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 4802dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 48120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 48220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 48393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 484acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong if (mTracks.empty()) { 485acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong ALOGE("No source added"); 486acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return INVALID_OPERATION; 487acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 488acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 489a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 490a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 49193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 492a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 493a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 494a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 495a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 496a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 497a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 498a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 499a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 500a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 501a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 502a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 503a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 504a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 5052dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 5062dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 5072dec2b5be2056c6d9428897dc672185872d30d17James Dong // 5082dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 5092dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 5102dec2b5be2056c6d9428897dc672185872d30d17James Dong 51178a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 5122dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 51378a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 3 5142dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 5152dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 5162dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 5172dec2b5be2056c6d9428897dc672185872d30d17James Dong 5182dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 5192dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 5202dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 52178a1a286f736888ae7af8860b2c424af0d978848James Dong static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 5222dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 5232dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 5242dec2b5be2056c6d9428897dc672185872d30d17James Dong 52578a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file size limit is set 526a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 52778a1a286f736888ae7af8860b2c424af0d978848James Dong size = mMaxFileSizeLimitBytes * 6 / 1000; 52878a1a286f736888ae7af8860b2c424af0d978848James Dong } 52978a1a286f736888ae7af8860b2c424af0d978848James Dong 53078a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file duration limit is set 53178a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileDurationLimitUs != 0) { 53278a1a286f736888ae7af8860b2c424af0d978848James Dong if (bitRate > 0) { 53378a1a286f736888ae7af8860b2c424af0d978848James Dong int64_t size2 = 53478a1a286f736888ae7af8860b2c424af0d978848James Dong ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 53578a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 53678a1a286f736888ae7af8860b2c424af0d978848James Dong // When both file size and duration limits are set, 53778a1a286f736888ae7af8860b2c424af0d978848James Dong // we use the smaller limit of the two. 53878a1a286f736888ae7af8860b2c424af0d978848James Dong if (size > size2) { 53978a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 54078a1a286f736888ae7af8860b2c424af0d978848James Dong } 54178a1a286f736888ae7af8860b2c424af0d978848James Dong } else { 54278a1a286f736888ae7af8860b2c424af0d978848James Dong // Only max file duration limit is set 54378a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 54478a1a286f736888ae7af8860b2c424af0d978848James Dong } 5452dec2b5be2056c6d9428897dc672185872d30d17James Dong } 5462dec2b5be2056c6d9428897dc672185872d30d17James Dong } 54778a1a286f736888ae7af8860b2c424af0d978848James Dong 5482dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 5492dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 5502dec2b5be2056c6d9428897dc672185872d30d17James Dong } 5512dec2b5be2056c6d9428897dc672185872d30d17James Dong 5522dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 5532dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 5542dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 5552dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 5562dec2b5be2056c6d9428897dc672185872d30d17James Dong } 5572dec2b5be2056c6d9428897dc672185872d30d17James Dong 558a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the" 559a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn " estimated moov size %" PRId64 " bytes", 5602dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 5612dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 5622dec2b5be2056c6d9428897dc672185872d30d17James Dong} 5632dec2b5be2056c6d9428897dc672185872d30d17James Dong 5642dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 565674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 56625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 56720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 56820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 569a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong /* 570a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * Check mMaxFileSizeLimitBytes at the beginning 571a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * since mMaxFileSizeLimitBytes may be implicitly 572a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * changed later for 32-bit file offset even if 573a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * user does not ask to set it explicitly. 574a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong */ 575a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0) { 576a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested = true; 577a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong } 578a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong 5792dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 5802dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 5812dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 5822dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 5832dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 5842dec2b5be2056c6d9428897dc672185872d30d17James Dong } 5852dec2b5be2056c6d9428897dc672185872d30d17James Dong 5861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mUse32BitOffset) { 5871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // Implicit 32 bit file size limit 5881f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes == 0) { 5891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 5901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 5911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 5921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // If file size is set to be larger than the 32 bit file 5931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // size limit, treat it as an error. 5941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 595a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. " 596a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn "It is changed to %" PRId64 " bytes", 597d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes, kMax32BitFileSize); 598d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 5991f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 6001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 6011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 602b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong int32_t use2ByteNalLength; 603b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (param && 604b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 605b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong use2ByteNalLength) { 606b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength = false; 6072dec2b5be2056c6d9428897dc672185872d30d17James Dong } 6082dec2b5be2056c6d9428897dc672185872d30d17James Dong 609de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui int32_t isRealTimeRecording; 610de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) { 611de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mIsRealTimeRecording = isRealTimeRecording; 612de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 613de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui 614065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 61593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 616a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 617a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 618a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 61993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 620a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 621a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 622a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 623a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 6248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 6258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 6268f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 6278f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 62843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mTimeScale, 0); 6293856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("movie time scale: %d", mTimeScale); 6308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 63177e8ae9967a078770416619e99ddb5b010def312James Dong /* 63277e8ae9967a078770416619e99ddb5b010def312James Dong * When the requested file size limit is small, the priority 63377e8ae9967a078770416619e99ddb5b010def312James Dong * is to meet the file size limit requirement, rather than 6347b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * to make the file streamable. mStreamableFile does not tell 6357b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * whether the actual recorded file is streamable or not. 63677e8ae9967a078770416619e99ddb5b010def312James Dong */ 63777e8ae9967a078770416619e99ddb5b010def312James Dong mStreamableFile = 63877e8ae9967a078770416619e99ddb5b010def312James Dong (mMaxFileSizeLimitBytes != 0 && 63977e8ae9967a078770416619e99ddb5b010def312James Dong mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes); 64077e8ae9967a078770416619e99ddb5b010def312James Dong 6417b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong /* 6427b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * mWriteMoovBoxToMemory is true if the amount of data in moov box is 6437b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * smaller than the reserved free space at the beginning of a file, AND 6447b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * when the content of moov box is constructed. Note that video/audio 6457b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * frame data is always written to the file but not in the memory. 6467b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 6477b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * Before stop()/reset() is called, mWriteMoovBoxToMemory is always 6487b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * false. When reset() is called at the end of a recording session, 6497b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * Moov box needs to be constructed. 6507b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 6517b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory 6527b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * to set to mStreamableFile so that if 6537b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * the file is intended to be streamable, it is set to true; 6547b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * otherwise, it is set to false. When the value is set to false, 6557b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * all the content of the moov box is written immediately to 6567b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * the end of the file. When the value is set to true, all the 6577b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * content of the moov box is written to an in-memory cache, 6587b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * mMoovBoxBuffer, util the following condition happens. Note 6597b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * that the size of the in-memory cache is the same as the 6607b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * reserved free space at the beginning of the file. 6617b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 6627b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 2) While the data of the moov box is written to an in-memory 6637b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * cache, the data size is checked against the reserved space. 6647b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * If the data size surpasses the reserved space, subsequent moov 6657b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * data could no longer be hold in the in-memory cache. This also 6667b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * indicates that the reserved space was too small. At this point, 6677b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * _all_ moov data must be written to the end of the file. 6687b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * mWriteMoovBoxToMemory must be set to false to direct the write 6697b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * to the file. 6707b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 6717b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 3) If the data size in moov box is smaller than the reserved 6727b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * space after moov box is completely constructed, the in-memory 6737b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * cache copy of the moov box is written to the reserved free 6747b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * space. Thus, immediately after the moov is completedly 6757b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * constructed, mWriteMoovBoxToMemory is always set to false. 6767b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong */ 6777b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mWriteMoovBoxToMemory = false; 6787837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6797837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6807837c17063a4c50bc856ba59418516fdab731de7James Dong 681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFtypBox(param); 68220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6837837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 68420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6857837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 6862dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 6872dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 6882dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 6892dec2b5be2056c6d9428897dc672185872d30d17James Dong } 6902dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 6917837c17063a4c50bc856ba59418516fdab731de7James Dong } 69243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GE(mEstimatedMoovBoxSize, 8); 69377e8ae9967a078770416619e99ddb5b010def312James Dong if (mStreamableFile) { 69477e8ae9967a078770416619e99ddb5b010def312James Dong // Reserve a 'free' box only for streamable file 69577e8ae9967a078770416619e99ddb5b010def312James Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 69677e8ae9967a078770416619e99ddb5b010def312James Dong writeInt32(mEstimatedMoovBoxSize); 69777e8ae9967a078770416619e99ddb5b010def312James Dong write("free", 4); 69877e8ae9967a078770416619e99ddb5b010def312James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 69977e8ae9967a078770416619e99ddb5b010def312James Dong } else { 70077e8ae9967a078770416619e99ddb5b010def312James Dong mMdatOffset = mOffset; 70177e8ae9967a078770416619e99ddb5b010def312James Dong } 7027837c17063a4c50bc856ba59418516fdab731de7James Dong 7037837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 704c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 7051acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 7061acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 7071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 7081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 7091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 7101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 7111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 7121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 7131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 7141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 7151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 7161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 717a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 718a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 71920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 7201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 721a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 72225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 72320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 72420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const { 7261f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong return mUse32BitOffset; 7271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 7281f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 72937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 730674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 73137187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 732a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 733a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 73437187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 735a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 736a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 73737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 73837187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 73937187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 74037187916a486504acaf83bea30147eb5fbf46ae5James Dong } 741a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 74237187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 743a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 744a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 7451c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 746b8a805261bf0282e992d3608035e47d05a898710Steve Block ALOGD("Stopping writer thread"); 747411ba422e3635d534928ffd81abf54f4f291c739James Dong if (!mWriterThreadStarted) { 748411ba422e3635d534928ffd81abf54f4f291c739James Dong return; 749411ba422e3635d534928ffd81abf54f4f291c739James Dong } 7501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 7511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 7521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 7531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 7541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 7551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 7561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 7571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 7581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 7591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 760411ba422e3635d534928ffd81abf54f4f291c739James Dong mWriterThreadStarted = false; 761b8a805261bf0282e992d3608035e47d05a898710Steve Block ALOGD("Writer thread stopped"); 7621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 7631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 76413f6284305e4b27395a23db7882d670bdb1bcae1James Dong/* 76513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix: 76613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a b u | 76713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c d v | 76813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x y w | 76913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * 77013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following 77113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w}, 77213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while 77313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format. 77413f6284305e4b27395a23db7882d670bdb1bcae1James Dong */ 77513f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) { 7763856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("writeCompositionMatrix"); 77713f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t a = 0x00010000; 77813f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t b = 0; 77913f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t c = 0; 78013f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t d = 0x00010000; 78113f6284305e4b27395a23db7882d670bdb1bcae1James Dong switch (degrees) { 78213f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 0: 78313f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 78413f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 90: 78513f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 78613f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0x00010000; 78713f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0xFFFF0000; 78813f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 78913f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 79013f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 180: 79113f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0xFFFF0000; 79213f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0xFFFF0000; 79313f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 79413f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 270: 79513f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 79613f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0xFFFF0000; 79713f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0x00010000; 79813f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 79913f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 80013f6284305e4b27395a23db7882d670bdb1bcae1James Dong default: 80113f6284305e4b27395a23db7882d670bdb1bcae1James Dong CHECK(!"Should never reach this unknown rotation"); 80213f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 80313f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 80413f6284305e4b27395a23db7882d670bdb1bcae1James Dong 80513f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(a); // a 80613f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(b); // b 80713f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // u 80813f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(c); // c 80913f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(d); // d 81013f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // v 81113f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // x 81213f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // y 81313f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0x40000000); // w 81413f6284305e4b27395a23db7882d670bdb1bcae1James Dong} 81513f6284305e4b27395a23db7882d670bdb1bcae1James Dong 816411ba422e3635d534928ffd81abf54f4f291c739James Dongvoid MPEG4Writer::release() { 817411ba422e3635d534928ffd81abf54f4f291c739James Dong close(mFd); 818411ba422e3635d534928ffd81abf54f4f291c739James Dong mFd = -1; 819411ba422e3635d534928ffd81abf54f4f291c739James Dong mInitCheck = NO_INIT; 820411ba422e3635d534928ffd81abf54f4f291c739James Dong mStarted = false; 821411ba422e3635d534928ffd81abf54f4f291c739James Dong} 82213f6284305e4b27395a23db7882d670bdb1bcae1James Dong 8238bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dongstatus_t MPEG4Writer::reset() { 824674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 82537187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 826411ba422e3635d534928ffd81abf54f4f291c739James Dong } else { 827411ba422e3635d534928ffd81abf54f4f291c739James Dong if (!mWriterThreadStarted || 828411ba422e3635d534928ffd81abf54f4f291c739James Dong !mStarted) { 829411ba422e3635d534928ffd81abf54f4f291c739James Dong if (mWriterThreadStarted) { 830411ba422e3635d534928ffd81abf54f4f291c739James Dong stopWriterThread(); 831411ba422e3635d534928ffd81abf54f4f291c739James Dong } 832411ba422e3635d534928ffd81abf54f4f291c739James Dong release(); 833411ba422e3635d534928ffd81abf54f4f291c739James Dong return OK; 834411ba422e3635d534928ffd81abf54f4f291c739James Dong } 83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 83620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 8388f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 83965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong int64_t minDurationUs = 0x7fffffffffffffffLL; 84020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 84120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 84237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 84337187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 84437187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 84537187916a486504acaf83bea30147eb5fbf46ae5James Dong } 84620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8478f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 8488f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 8498f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 85020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 85165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (durationUs < minDurationUs) { 85265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs = durationUs; 85365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 85465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 85565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong 85665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (mTracks.size() > 1) { 857a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", 85865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs, maxDurationUs); 85920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 86020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 8627837c17063a4c50bc856ba59418516fdab731de7James Dong 86337187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 86437187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 865411ba422e3635d534928ffd81abf54f4f291c739James Dong release(); 86637187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 86737187916a486504acaf83bea30147eb5fbf46ae5James Dong } 86837187916a486504acaf83bea30147eb5fbf46ae5James Dong 86920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 8701acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 871c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 8721f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset)); 873c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 4); 8741acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 875c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset + 8, SEEK_SET); 8761f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad uint64_t size = mOffset - mMdatOffset; 8771acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 878c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 8); 8791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 880c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 88120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8827b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // Construct moov box now 8837837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 8847b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mWriteMoovBoxToMemory = mStreamableFile; 8857b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong if (mWriteMoovBoxToMemory) { 8867b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // There is no need to allocate in-memory cache 8877b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // for moov box if the file is not streamable. 8887b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 8897b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 8907b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong CHECK(mMoovBoxBuffer != NULL); 8917b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong } 892b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMoovBox(maxDurationUs); 89320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8947b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // mWriteMoovBoxToMemory could be set to false in 8957b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // MPEG4Writer::write() method 8967b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong if (mWriteMoovBoxToMemory) { 8977b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mWriteMoovBoxToMemory = false; 8987b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // Content of the moov box is saved in the cache, and the in-memory 8997b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // moov box needs to be written to the file in a single shot. 9007b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 90143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize); 9027837c17063a4c50bc856ba59418516fdab731de7James Dong 9037837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 904c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 9057837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 906674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 9077837c17063a4c50bc856ba59418516fdab731de7James Dong 9087837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 909c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 9107837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 9117837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 9127b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong } else { 9137b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong ALOGI("The mp4 file will not be streamable."); 9147b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong } 9157837c17063a4c50bc856ba59418516fdab731de7James Dong 9167b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // Free in-memory cache for moov box 9177b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong if (mMoovBoxBuffer != NULL) { 9187837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 9197837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 9207837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 9217837c17063a4c50bc856ba59418516fdab731de7James Dong } 9227837c17063a4c50bc856ba59418516fdab731de7James Dong 9230c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 925411ba422e3635d534928ffd81abf54f4f291c739James Dong release(); 92637187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 92820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 929efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonuint32_t MPEG4Writer::getMpeg4Time() { 930b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong time_t now = time(NULL); 931efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson // MP4 file uses time counting seconds since midnight, Jan. 1, 1904 932efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson // while time function returns Unix epoch values which starts 933efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson // at 1970-01-01. Lets add the number of seconds between them 934efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60); 935efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson return mpeg4Time; 936efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson} 937efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson 938efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) { 939efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson uint32_t now = getMpeg4Time(); 940b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("mvhd"); 941b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // version=0, flags=0 942b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // creation time 943b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // modification time 944b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTimeScale); // mvhd timescale 945b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; 946b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(duration); 947b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0x10000); // rate: 1.0 948b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0x100); // volume 949b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0); // reserved 950b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 951b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 952b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeCompositionMatrix(0); // matrix 953b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 954b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 955b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 956b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 957b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 958b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 959b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTracks.size() + 1); // nextTrackID 960b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // mvhd 961b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 962b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 963b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) { 964b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("moov"); 965b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMvhdBox(durationUs); 96607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (mAreGeoTagsAvailable) { 96707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeUdtaBox(); 96807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 969b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t id = 1; 970b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<Track *>::iterator it = mTracks.begin(); 971b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mTracks.end(); ++it, ++id) { 972b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (*it)->writeTrackHeader(mUse32BitOffset); 973b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 974b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // moov 975b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 976b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 9772cf9c5073ca3342ee52673ad68763fadd2c2be79James Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) { 978b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("ftyp"); 979b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 980b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t fileType; 981b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (param && param->findInt32(kKeyFileType, &fileType) && 982b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fileType != OUTPUT_FORMAT_MPEG_4) { 983b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("3gp4"); 9848284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeInt32(0); 9858284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("isom"); 9868284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("3gp4"); 987b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 9888284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("mp42"); 9898284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeInt32(0); 990b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("isom"); 9918284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("mp42"); 992b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 993b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 994b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); 995b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 996b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 99707ec01904613a0bac32caaa8444b4690998faed7James Dongstatic bool isTestModeEnabled() { 99807ec01904613a0bac32caaa8444b4690998faed7James Dong#if (PROPERTY_VALUE_MAX < 5) 99907ec01904613a0bac32caaa8444b4690998faed7James Dong#error "PROPERTY_VALUE_MAX must be at least 5" 100007ec01904613a0bac32caaa8444b4690998faed7James Dong#endif 100107ec01904613a0bac32caaa8444b4690998faed7James Dong 100207ec01904613a0bac32caaa8444b4690998faed7James Dong // Test mode is enabled only if rw.media.record.test system 100307ec01904613a0bac32caaa8444b4690998faed7James Dong // property is enabled. 100407ec01904613a0bac32caaa8444b4690998faed7James Dong char value[PROPERTY_VALUE_MAX]; 100507ec01904613a0bac32caaa8444b4690998faed7James Dong if (property_get("rw.media.record.test", value, NULL) && 100607ec01904613a0bac32caaa8444b4690998faed7James Dong (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) { 100707ec01904613a0bac32caaa8444b4690998faed7James Dong return true; 100807ec01904613a0bac32caaa8444b4690998faed7James Dong } 100907ec01904613a0bac32caaa8444b4690998faed7James Dong return false; 101007ec01904613a0bac32caaa8444b4690998faed7James Dong} 101107ec01904613a0bac32caaa8444b4690998faed7James Dong 101270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() { 101307ec01904613a0bac32caaa8444b4690998faed7James Dong // Send session summary only if test mode is enabled 101407ec01904613a0bac32caaa8444b4690998faed7James Dong if (!isTestModeEnabled()) { 101507ec01904613a0bac32caaa8444b4690998faed7James Dong return; 101607ec01904613a0bac32caaa8444b4690998faed7James Dong } 101707ec01904613a0bac32caaa8444b4690998faed7James Dong 101870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 101970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it != mChunkInfos.end(); ++it) { 102070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int trackNum = it->mTrack->getTrackId() << 28; 102170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 102270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, 102370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs); 102470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 102570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong} 102670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 102713aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 102813aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 102913aec890216948b0c364f8f92792129d0335f506James Dong return OK; 103013aec890216948b0c364f8f92792129d0335f506James Dong} 103113aec890216948b0c364f8f92792129d0335f506James Dong 103213aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 103313aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 103413aec890216948b0c364f8f92792129d0335f506James Dong} 103513aec890216948b0c364f8f92792129d0335f506James Dong 103613aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 103713aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 103813aec890216948b0c364f8f92792129d0335f506James Dong} 103920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1040c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 1041c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 104220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1043c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 1044c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 1045c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong buffer->range_length()); 104620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 104820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 105020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 105120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 105203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 105303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 105403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 105503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 105603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 105703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 105803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 105903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 106003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 106103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 106203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 106303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 106403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 106503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1066c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 1067c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 106830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 106930ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 107003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1071b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mUse4ByteNalLength) { 1072b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 24; 1073c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1074b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 16) & 0xff; 1075c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1076b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 8) & 0xff; 1077c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1078b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 1079c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1080c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong 1081c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 1082c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 1083c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong length); 1084b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 1085b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 4; 1086b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 108743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LT(length, 65536); 108830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1089b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 8; 1090c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1091b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 1092c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1093c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 1094b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 2; 1095b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 109630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 109730ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 109830ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 109930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 11007837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 1101674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong const void *ptr, size_t size, size_t nmemb) { 11027837c17063a4c50bc856ba59418516fdab731de7James Dong 11037837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 11047837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 11057b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 1106c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 11071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 11087b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // The reserved moov box at the beginning of the file 11097b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // is not big enough. Moov box should be written to 11107b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // the end of the file from now on, but not to the 11117b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // in-memory cache. 11127b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 11137b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // We write partial moov box that is in the memory to 11147b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // the file first. 1115c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mBoxes.begin(); 11167837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 11177837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 11187837c17063a4c50bc856ba59418516fdab731de7James Dong } 1119674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong lseek64(mFd, mOffset, SEEK_SET); 1120674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 11217b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong ::write(mFd, ptr, bytes); 11227837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 11237b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 11247b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // All subsequent moov box content will be written 11257b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // to the end of the file. 11267837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 11277837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 11287837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 11297837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 11307837c17063a4c50bc856ba59418516fdab731de7James Dong } 11317837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 1132674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 11337837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 11347837c17063a4c50bc856ba59418516fdab731de7James Dong } 11357837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 11367837c17063a4c50bc856ba59418516fdab731de7James Dong} 11377837c17063a4c50bc856ba59418516fdab731de7James Dong 113820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 11390c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 114020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 11417837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 11427837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 114320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 114420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 114520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 114620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 114720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 114820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 11490c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 115020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1151c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = *--mBoxes.end(); 115220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 115320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 11547837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 11557837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 11567837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 11577837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 1158c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, offset, SEEK_SET); 11597837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 11607837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 1161c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 11627837c17063a4c50bc856ba59418516fdab731de7James Dong } 116320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 116420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 116520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 1166674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 1); 116720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 116820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 116920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 117020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 1171674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 2); 117220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 117320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 117420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 117520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 1176674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 4); 117720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 117820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 117920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 118020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 1181674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 8); 118220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 118320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 118420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 118520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 1186674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, n + 1); 118720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 118820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 118920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 11900c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 1191674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, 4); 119220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 119320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 119407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 119507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format 119607b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) { 119707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 119807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 119907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 120007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 120107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[9]; 120207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 120307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 120407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%c%.2d.", sign, wholePart); 120507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 120607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%+.2d.", wholePart); 120707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 120807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 120907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 121007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 121107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 121207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 121307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 121407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[4], 5, "%.4d", fractionalPart); 121507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 121607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 121707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 8); 121807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 121907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 122007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format 122107b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) { 122207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 122307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 122407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 122507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 122607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[10]; 122707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 122807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 122907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%c%.3d.", sign, wholePart); 123007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 123107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%+.3d.", wholePart); 123207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 123307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 123407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 123507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 123607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 123707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 123807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 123907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[5], 5, "%.4d", fractionalPart); 124007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 124107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 124207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 9); 124307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 124407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 124507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 124607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 124707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and 124807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000. 124907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and 125007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180] 125107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 125207b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { 125307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Is latitude or longitude out of range? 125407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (latitudex10000 < -900000 || latitudex10000 > 900000 || 125507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong longitudex10000 < -1800000 || longitudex10000 > 1800000) { 125607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return BAD_VALUE; 125707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 125807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 125907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000 = latitudex10000; 126007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000 = longitudex10000; 126107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mAreGeoTagsAvailable = true; 126207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return OK; 126307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 126407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 126520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 1266674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(data, 1, size); 126720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 126820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 126978a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const { 127078a1a286f736888ae7af8860b2c424af0d978848James Dong return mStreamableFile; 127178a1a286f736888ae7af8860b2c424af0d978848James Dong} 127278a1a286f736888ae7af8860b2c424af0d978848James Dong 1273d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 1274d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1275d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 1276d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1277d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1278d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1279956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 1280d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1281d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1282d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1283d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 12841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 128577e8ae9967a078770416619e99ddb5b010def312James Dong if (!mStreamableFile) { 128677e8ae9967a078770416619e99ddb5b010def312James Dong // Add 1024 bytes as error tolerance 128777e8ae9967a078770416619e99ddb5b010def312James Dong return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes; 128877e8ae9967a078770416619e99ddb5b010def312James Dong } 1289acd234bba9f048971d66890009eeff9a8db94be3James Dong // Be conservative in the estimate: do not exceed 95% of 1290acd234bba9f048971d66890009eeff9a8db94be3James Dong // the target file limit. For small target file size limit, though, 1291acd234bba9f048971d66890009eeff9a8db94be3James Dong // this will not help. 1292acd234bba9f048971d66890009eeff9a8db94be3James Dong return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 1293d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1294d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1295d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 1296d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1297d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 1298d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1299d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1300d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1301d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1302d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1303d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 1304d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 1305d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1306d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1307d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1308d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1309d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 131025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 131125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 131225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 131325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 131425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 131525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 131625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 131725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 131825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 131925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 132025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 132125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 132225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 1323f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 1324a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("setStartTimestampUs: %" PRId64, timeUs); 132543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GE(timeUs, 0ll); 13263c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 1327065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 1328f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 1329a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs); 13303c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 13313c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 13323c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 1333f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 13343c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 13353c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 13363c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 13373c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 133858ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 133958ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 134058ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 134158ae9c530247668f8af36e30d228c716c226b3d4James Dong} 134258ae9c530247668f8af36e30d228c716c226b3d4James Dong 134320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 134420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 134520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 1346bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) 134720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 134825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 134920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 135020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 1351a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 1352a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 1353eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted(false), 1354bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mTrackId(trackId), 1355c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 1356956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 1357be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 1358c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1359c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1360c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)), 1361c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)), 1362c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1363c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 1364c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 136520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 136625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 1367548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 136813f6284305e4b27395a23db7882d670bdb1bcae1James Dong mReachedEOS(false), 136913f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation(0) { 137019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 13718f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 13721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 13731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 13741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 13751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 13761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 13771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 13781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1379c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 1380c059860c73678a202bfa33062723e8f82fb779d9James Dong} 1381c059860c73678a202bfa33062723e8f82fb779d9James Dong 13821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() { 13831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1384c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t stcoBoxCount = (mOwner->use32BitFileOffset() 1385c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ? mStcoTableEntries->count() 1386c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong : mCo64TableEntries->count()); 1387c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong int64_t stcoBoxSizeBytes = stcoBoxCount * 4; 1388c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4); 13891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 139078a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 139178a1a286f736888ae7af8860b2c424af0d978848James Dong if (!mOwner->isFileStreamable()) { 139278a1a286f736888ae7af8860b2c424af0d978848James Dong // Reserved free space is not large enough to hold 139378a1a286f736888ae7af8860b2c424af0d978848James Dong // all meta data and thus wasted. 1394c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 + // stsc box size 1395c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries->count() * 4 + // stss box size 1396c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->count() * 8 + // stts box size 1397c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->count() * 8 + // ctts box size 139878a1a286f736888ae7af8860b2c424af0d978848James Dong stcoBoxSizeBytes + // stco box size 139978a1a286f736888ae7af8860b2c424af0d978848James Dong stszBoxSizeBytes; // stsz box size 140078a1a286f736888ae7af8860b2c424af0d978848James Dong } 14011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 14021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 14031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry( 14041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t chunkId, size_t sampleId) { 14051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1406c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->add(htonl(chunkId)); 1407c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->add(htonl(sampleId)); 1408c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->add(htonl(1)); 14091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 14101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 14111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 1412c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries->add(htonl(sampleId)); 14131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 14141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 14151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry( 141679761ab096f57c3027fad9556c2bc436672d614eJames Dong size_t sampleCount, int32_t duration) { 14171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 14185a217fba010e801c255503602bda4b86ac5a6ac9James Dong if (duration == 0) { 1419377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGW("0-duration samples found: %zu", sampleCount); 14205a217fba010e801c255503602bda4b86ac5a6ac9James Dong } 1421c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->add(htonl(sampleCount)); 1422c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->add(htonl(duration)); 14231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 14241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1425965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::addOneCttsTableEntry( 1426965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong size_t sampleCount, int32_t duration) { 1427965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 1428965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong if (mIsAudio) { 1429965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong return; 1430965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 1431c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->add(htonl(sampleCount)); 1432c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->add(htonl(duration)); 1433965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong} 1434965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 1435c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) { 1436c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mOwner->use32BitFileOffset()) { 1437c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t value = offset; 1438c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries->add(htonl(value)); 1439c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } else { 1440c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries->add(hton64(offset)); 1441c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 14421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 14431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1444c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 14453856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("setTimeScale"); 1446c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 1447c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 1448c059860c73678a202bfa33062723e8f82fb779d9James Dong 1449c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 1450c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 1451c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 1452c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1453c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 1454c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 1455c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1456c059860c73678a202bfa33062723e8f82fb779d9James Dong 1457c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 1458c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 1459c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1460c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 1461c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1462c059860c73678a202bfa33062723e8f82fb779d9James Dong 146343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mTimeScale, 0); 146419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 146519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 146619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 146719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 146819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 146919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 147019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 147119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 147219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 147319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 147419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 147519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 147619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 147719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 147819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 147919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 148019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 148119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 148219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 148319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 148419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 148519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 148619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 148719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 148819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 148919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 149019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 149119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 149219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 149319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 149419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 149520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 149620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 149720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 149820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 149920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1500c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStszTableEntries; 1501c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStcoTableEntries; 1502c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mCo64TableEntries; 1503c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStscTableEntries; 1504c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mSttsTableEntries; 1505c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStssTableEntries; 1506c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mCttsTableEntries; 1507c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 1508c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries = NULL; 1509c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries = NULL; 1510c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries = NULL; 1511c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries = NULL; 1512c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries = NULL; 1513c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries = NULL; 1514c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries = NULL; 1515c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 151620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 151720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 151820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 151920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 152020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 152120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 152293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 15233856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("initTrackingProgressStatus"); 152493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 152593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 152693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 152793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 152893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 152993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 1530a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); 153193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 153293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 153393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 153493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 153593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 153693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 15371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 15381c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 15393856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("ThreadWrapper: %p", me); 15401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 15411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 15421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 15431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 15441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 15451c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 15463856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("bufferChunk: %p", chunk.mTrack); 15471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 15481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 15491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 15501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 15511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 15521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 15531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 15541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 15551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 15561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 15571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 15581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 15591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 156043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK(!"Received a chunk for a unknown track"); 15611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 15621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1563fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) { 1564a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("writeChunkToFile: %" PRId64 " from %s track", 15655410afcbb0af5d29d9f710a1c2978c500f9792dcPannag Sanketi chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video"); 1566fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1567fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong int32_t isFirstSample = true; 1568fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!chunk->mSamples.empty()) { 1569fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 1570fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1571fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong off64_t offset = chunk->mTrack->isAvc() 1572fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong ? addLengthPrefixedSample_l(*it) 1573fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong : addSample_l(*it); 1574fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1575fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (isFirstSample) { 1576fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mTrack->addChunkOffset(offset); 1577fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong isFirstSample = false; 15781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 15791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 15801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 15811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 1582fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.erase(it); 15831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1584fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.clear(); 15851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 15861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1587fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() { 15883856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("writeAllChunks"); 15891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 159070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong Chunk chunk; 159170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong while (findChunkToWrite(&chunk)) { 1592e9f6d0579603372fd2547e6c5ba6e114c6f8cba7James Dong writeChunkToFile(&chunk); 159370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong ++outstandingChunks; 15941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 159570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 159670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong sendSessionSummary(); 159770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 15981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 1599377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGD("%zu chunks are written in the last batch", outstandingChunks); 16001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 16011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1602fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 16033856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("findChunkToWrite"); 16041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 16061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 16071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 16081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 16091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 16101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 16111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 16121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 16131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 16141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 16193856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Nothing to be written after all"); 1620fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 16211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 16241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 16251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1626fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 16271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 16281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 16291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 1630fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong *chunk = *(it->mChunks.begin()); 1631fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong it->mChunks.erase(it->mChunks.begin()); 1632fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong CHECK_EQ(chunk->mTrack, track); 163370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 163470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t interChunkTimeUs = 163570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 163670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 163770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs = interChunkTimeUs; 163870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 163970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 1640fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return true; 16411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1643fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1644fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 16451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 16461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16471c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 16483856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("threadFunc"); 16491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1650a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 1651fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1652fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Mutex::Autolock autoLock(mLock); 16531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 1654fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Chunk chunk; 1655fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong bool chunkFound = false; 1656fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1657fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 16581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 16591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1661de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // In real time recording mode, write without holding the lock in order 1662de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // to reduce the blocking time for media track threads. 1663de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // Otherwise, hold the lock until the existing chunks get written to the 1664de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // file. 1665fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (chunkFound) { 1666de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mIsRealTimeRecording) { 1667de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mLock.unlock(); 1668de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 1669fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeChunkToFile(&chunk); 1670de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mIsRealTimeRecording) { 1671de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mLock.lock(); 1672de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 1673fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong } 16741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1675fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1676fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeAllChunks(); 16771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 16781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16791c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 16803856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("startWriterThread"); 16811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 16831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1684e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 16851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 16861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 16871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 16881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 168970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mPrevChunkTimestampUs = 0; 169070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mMaxInterChunkDurUs = 0; 16911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 16921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 16951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 16961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 16971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 16981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 1699411ba422e3635d534928ffd81abf54f4f291c739James Dong mWriterThreadStarted = true; 17001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 17011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 17021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 170493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1705a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1706a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1707a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1708a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1709a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 171025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 171193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 171219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 171319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 171419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 171570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mStartTimeRealUs = startTimeUs; 171619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 171713f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t rotationDegrees; 171813f6284305e4b27395a23db7882d670bdb1bcae1James Dong if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 171913f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation = rotationDegrees; 172013f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 172113f6284305e4b27395a23db7882d670bdb1bcae1James Dong 172293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 172393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1724f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1725de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) { 1726a472613aec322e25891abf5c77bf3f7e3c244920James Dong /* 1727a472613aec322e25891abf5c77bf3f7e3c244920James Dong * This extra delay of accepting incoming audio/video signals 1728a472613aec322e25891abf5c77bf3f7e3c244920James Dong * helps to align a/v start time at the beginning of a recording 1729a472613aec322e25891abf5c77bf3f7e3c244920James Dong * session, and it also helps eliminate the "recording" sound for 1730a472613aec322e25891abf5c77bf3f7e3c244920James Dong * camcorder applications. 1731a472613aec322e25891abf5c77bf3f7e3c244920James Dong * 173286b7f47aa7482424cf8fd248f1315311919be3b0James Dong * If client does not set the start time offset, we fall back to 173386b7f47aa7482424cf8fd248f1315311919be3b0James Dong * use the default initial delay value. 1734a472613aec322e25891abf5c77bf3f7e3c244920James Dong */ 173586b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 173686b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 173786b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 173886b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 173986b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeUs += startTimeOffsetUs; 1740a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 1741a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 1742a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1743f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1744a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1745f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 174625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 174725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 174825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 174925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 175020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 175120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 175220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 175320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 175420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 175520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1756eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted = true; 1757c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 175825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1759956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 17601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes = 0; 176143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = 0; 176220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 176325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 176420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 176525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 176625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 176720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 176820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 176937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1770a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 177137187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1772a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1773a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 177437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 177572cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang ALOGD("%s track stopping", mIsAudio? "Audio": "Video"); 1776eaae38445a340c4857c1c5569475879a728e63b7James Dong if (!mStarted) { 177729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Stop() called but track is not started"); 1778eaae38445a340c4857c1c5569475879a728e63b7James Dong return ERROR_END_OF_STREAM; 1779eaae38445a340c4857c1c5569475879a728e63b7James Dong } 1780eaae38445a340c4857c1c5569475879a728e63b7James Dong 178120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 178237187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 178320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 178420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 178520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 178672cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); 178772cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang mSource->stop(); 178872cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang ALOGD("%s track source stopped", mIsAudio? "Audio": "Video"); 178972cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang 179020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 179120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 1792377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); 179337187916a486504acaf83bea30147eb5fbf46ae5James Dong 1794b8a805261bf0282e992d3608035e47d05a898710Steve Block ALOGD("%s track stopped", mIsAudio? "Audio": "Video"); 179537187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 179620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 179720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 179825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 179925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 180025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 180125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 180220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 180320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 180420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 180520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 180637187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 1807377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT return (void *)(uintptr_t)err; 180820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 180920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 18113856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("getNalUnitType: %d", byte); 18123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 18143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 18153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 18163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 18183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 18193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1820a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("findNextStartCode: %p %zu", data, length); 18213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 18233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 18243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 18253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 18263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 18283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 18293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 18313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 18323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 18343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 18353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18363856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("parseParamSet"); 18373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 18383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 18393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 18413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 18423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 184329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Param set is malformed, since its length is 0"); 18443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 18453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 18483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 18493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 185029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Seq parameter set malformed"); 18513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 18523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 18543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 18553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 18563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 18573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 18583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 18593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 18603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 186129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Inconsistent profile/level found in seq parameter sets"); 18623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 18633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 18663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 18673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 18683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 18703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 18713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 18733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 18743856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("copyAVCCodecSpecificData"); 18753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 18773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 18783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 1879377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Codec specific data length too short: %zu", size); 18803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 18813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 18823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 18843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 18853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 18863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 18873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 18883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 18903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 18913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18923856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("parseAVCCodecSpecificData"); 18933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 18943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 18953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 18963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 18973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 18983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 18993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 19003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 19013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 19023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 19033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 19043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 19053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 19063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 19073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 190829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("SPS must come before PPS"); 19093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 19123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 19133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 19153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 19163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 191729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("SPS must come before PPS"); 19183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 19213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 19223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 19243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 192529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Only SPS and PPS Nal units are expected"); 19263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 19303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 19343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 19353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 19363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 19373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 19403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 19413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 19423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 194329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Cound not find sequence parameter set"); 19443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 1948377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets); 19493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 19543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 19553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 19563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 195729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Cound not find picture parameter set"); 19583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 1961377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets); 19623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19651374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// FIXME: 19661374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above 19671374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// and remove #if 0 19681374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#if 0 19693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 19703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 19713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 19723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 19733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 197429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 19753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 19763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19781374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#endif 19793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 19803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1981548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 198203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 198303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1984548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 198503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 198629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Already have codec specific data"); 198703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 198803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 198903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 19903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 1991377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Codec specific data length too short: %zu", size); 199203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 199303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 199403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 19953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 19963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 19973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 199803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 199903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 20003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 200103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 200203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 200303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 20043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 20053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 200603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 200703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 20083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 20093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 20103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 20113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 201203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 20133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 2014b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 2015b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 3; // length size == 4 bytes 2016b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 2017b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 1; // length size == 2 bytes 2018b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 201903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 20203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 20213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 20223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 20233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 20243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 20253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 20263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 20273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 20283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 20293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 20303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 20323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 20333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 20343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 20373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 20383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 20393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 20403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 20413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 20423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 20433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 20443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 20453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 20463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 20483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 20493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 20503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 205103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 205203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 205303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 205403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 2055872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 2056872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that 2057872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information 2058872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio 2059872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger 2060872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 2061872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined. 2062872a481558350634a3fd5cb67939de288af00ecbJames Dong */ 2063872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 2064872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftTimeUs = 0; 2065872a481558350634a3fd5cb67939de288af00ecbJames Dong if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 2066872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 2067872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 2068872a481558350634a3fd5cb67939de288af00ecbJames Dong mOwner->setDriftTimeUs(timeUs); 2069872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2070872a481558350634a3fd5cb67939de288af00ecbJames Dong} 2071872a481558350634a3fd5cb67939de288af00ecbJames Dong 207237187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 207330ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 207413aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 207543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong const bool hasMultipleTracks = (mOwner->numTracks() > 1); 207613aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 207713aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 207813aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 2079965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t lastTimestampUs = 0; // Previous sample time stamp 2080965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t lastDurationUs = 0; // Between the previous two samples 2081965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t currDurationTicks = 0; // Timescale based ticks 2082965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t lastDurationTicks = 0; // Timescale based ticks 2083965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 2084000e18370baae60ffd9f25b509501dd8c26deabfJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 2085a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 2086965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t timestampUs = 0; 2087000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t cttsOffsetTimeUs = 0; 2088000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks 2089000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks 209043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry 2091c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t lastSamplesPerChunk = 0; 2092e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2093a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong if (mIsAudio) { 2094a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 2095a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } else { 2096a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 2097a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } 2098de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui 2099de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mOwner->isRealTimeRecording()) { 2100de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); 2101de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 2102985f838934510983d8a887461e98dca60a6e858fJames Dong 2103d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 210420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 210593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 210620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 210711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih const char *trackName = mIsAudio ? "Audio" : "Video"; 210893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 210920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 211020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 211120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 211213aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 211320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 211420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 211520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2116a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 2117a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 2118a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 2119a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 2120a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 2121a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 2122a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 2123a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2124a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 212530ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 212630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 212703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 212803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 212903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 2130548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 2131548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 21321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 213303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 213403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 213503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 213603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 213743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_EQ((status_t)OK, err); 21381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 213903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 214003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 214103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 214203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 214303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 214403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 214530ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 214630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 214730ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 214830ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 214930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 2150548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 215130ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 2152a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2153a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2154d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 2155d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 2156d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 2157d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 2158d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 2159d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 2160d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 2161d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 2162d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 2163d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 21641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 2165e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 2166b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong size_t sampleSize = copy->range_length(); 2167b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mIsAvc) { 2168b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 2169b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 4; 2170b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 2171b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 2; 2172b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 2173b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 2174050b28a593350047845a45a14cc5026221ac1620James Dong 2175d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 21761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes += sampleSize; 21771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong updateTrackSizeEstimate(); 21781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 2179d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 2180d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2181d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2182d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2183d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 2184d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2185d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2186d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2187d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2188050b28a593350047845a45a14cc5026221ac1620James Dong 2189d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 2190d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2191d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 2192d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 2193d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 2194c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { 219570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mFirstSampleTimeRealUs = systemTime() / 1000; 2196f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 2197f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 21988428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs = mStartTimestampUs; 21993c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 220048c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 2201a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 22028428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 220311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { 220411f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 220511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 220611f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 220711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 22088428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 220911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { 221011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 221111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 221211f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 221311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 22148428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs += pausedDurationUs - lastDurationUs; 2215a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 2216a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2217a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2218a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 221911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 222011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 222111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 222211f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 222311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2224000e18370baae60ffd9f25b509501dd8c26deabfJames Dong if (!mIsAudio) { 2225965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong /* 2226965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong * Composition time: timestampUs 2227965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong * Decoding time: decodingTimeUs 2228000e18370baae60ffd9f25b509501dd8c26deabfJames Dong * Composition time offset = composition time - decoding time 2229965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong */ 2230965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t decodingTimeUs; 2231965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs)); 2232965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong decodingTimeUs -= previousPausedDurationUs; 2233000e18370baae60ffd9f25b509501dd8c26deabfJames Dong cttsOffsetTimeUs = 2234000e18370baae60ffd9f25b509501dd8c26deabfJames Dong timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; 223511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { 223611f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 223711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 223811f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 223911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2240965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong timestampUs = decodingTimeUs; 2241a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, 2242000e18370baae60ffd9f25b509501dd8c26deabfJames Dong timestampUs, cttsOffsetTimeUs); 2243000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 2244000e18370baae60ffd9f25b509501dd8c26deabfJames Dong // Update ctts box table if necessary 2245000e18370baae60ffd9f25b509501dd8c26deabfJames Dong currCttsOffsetTimeTicks = 2246000e18370baae60ffd9f25b509501dd8c26deabfJames Dong (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; 224711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { 224811f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 224911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 225011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 225111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2252c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { 225343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // Force the first ctts table entry to have one single entry 225443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // so that we can do adjustment for the initial track start 225543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // time offset easily in writeCttsBox(). 225643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 225743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong addOneCttsTableEntry(1, currCttsOffsetTimeTicks); 225843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong cttsSampleCount = 0; // No sample in ctts box is pending 225943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } else { 226043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) { 226143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 226243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 226343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong cttsSampleCount = 1; // One sample in ctts box is pending 226443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } else { 226543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong ++cttsSampleCount; 226643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 226743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 2268000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 2269000e18370baae60ffd9f25b509501dd8c26deabfJames Dong // Update ctts time offset range 2270c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { 2271000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2272000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2273000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } else { 2274000e18370baae60ffd9f25b509501dd8c26deabfJames Dong if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) { 2275000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2276000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) { 2277000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2278000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } 2279000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } 2280000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 2281965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 2282872a481558350634a3fd5cb67939de288af00ecbJames Dong 2283de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mOwner->isRealTimeRecording()) { 2284872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2285872a481558350634a3fd5cb67939de288af00ecbJames Dong updateDriftTime(meta_data); 2286e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2287e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2288872a481558350634a3fd5cb67939de288af00ecbJames Dong 228911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 229011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 229111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 229211f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 229311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2294a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, 229511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih trackName, timestampUs, previousPausedDurationUs); 2296c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 2297c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 22983b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 22993b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 23005a217fba010e801c255503602bda4b86ac5a6ac9James Dong // We need to use the time scale based ticks, rather than the 23015a217fba010e801c255503602bda4b86ac5a6ac9James Dong // timestamp itself to determine whether we have to use a new 23025a217fba010e801c255503602bda4b86ac5a6ac9James Dong // stts entry, since we may have rounding errors. 23035a217fba010e801c255503602bda4b86ac5a6ac9James Dong // The calculation is intended to reduce the accumulated 23045a217fba010e801c255503602bda4b86ac5a6ac9James Dong // rounding errors. 23055a217fba010e801c255503602bda4b86ac5a6ac9James Dong currDurationTicks = 23065a217fba010e801c255503602bda4b86ac5a6ac9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 23075a217fba010e801c255503602bda4b86ac5a6ac9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2308c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (currDurationTicks < 0ll) { 2309a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGE("timestampUs %" PRId64 " < lastTimestampUs %" PRId64 " for %s track", 231011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih timestampUs, lastTimestampUs, trackName); 231111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 2312c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong return UNKNOWN_ERROR; 23138c460498c028888c533ab442be12b6d4b669b965James Dong } 23148c460498c028888c533ab442be12b6d4b669b965James Dong 231585fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // if the duration is different for this sample, see if it is close enough to the previous 231685fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // duration that we can fudge it and use the same value, to avoid filling the stts table 231785fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // with lots of near-identical entries. 231885fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // "close enough" here means that the current duration needs to be adjusted by less 231985fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // than 0.1 milliseconds 232085fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { 232185fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL 232285fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen + (mTimeScale / 2)) / mTimeScale; 232385fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen if (deltaUs > -100 && deltaUs < 100) { 232485fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // use previous ticks, and adjust timestamp as if it was actually that number 232585fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // of ticks 232685fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen currDurationTicks = lastDurationTicks; 232785fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen timestampUs += deltaUs; 232885fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen } 232985fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen } 233085fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen 2331c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries->add(htonl(sampleSize)); 2332c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() > 2) { 2333c059860c73678a202bfa33062723e8f82fb779d9James Dong 2334a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Force the first sample to have its own stts entry so that 2335a472613aec322e25891abf5c77bf3f7e3c244920James Dong // we can adjust its value later to maintain the A/V sync. 2336c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) { 233779761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount, lastDurationTicks); 2338be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 2339be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2340be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 2341be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2342965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 2343be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2344be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 2345c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) { 2346be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 2347be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 23488644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 2349be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2350a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, 235111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih trackName, timestampUs, lastTimestampUs); 23528644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 2353c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 23548644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 235520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2356d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 2357c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong addOneStssTableEntry(mStszTableEntries->count()); 2358d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 2359d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 236093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 236193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 236293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 236393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 2364faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 236593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 236643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 2367c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 236858ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 2369c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 2370c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t count = (mOwner->use32BitFileOffset() 2371c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ? mStcoTableEntries->count() 2372c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong : mCo64TableEntries->count()); 2373c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 2374c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (count == 0) { 23751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addChunkOffset(offset); 237658ae9c530247668f8af36e30d228c716c226b3d4James Dong } 237758ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 237858ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 237958ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 238058ae9c530247668f8af36e30d228c716c226b3d4James Dong } 238113aec890216948b0c364f8f92792129d0335f506James Dong 238213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 238313aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 23841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, 1); 23851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 238613aec890216948b0c364f8f92792129d0335f506James Dong } else { 238713aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 238813aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 238913aec890216948b0c364f8f92792129d0335f506James Dong } else { 239043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 239143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > interleaveDurationUs) { 239243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > mMaxChunkDurationUs) { 239343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = chunkDurationUs; 239443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 239513aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 239613aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 2397c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong lastSamplesPerChunk != mChunkSamples.size()) { 2398c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong lastSamplesPerChunk = mChunkSamples.size(); 2399c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong addOneStscTableEntry(nChunks, lastSamplesPerChunk); 240013aec890216948b0c364f8f92792129d0335f506James Dong } 24011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 240213aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 240313aec890216948b0c364f8f92792129d0335f506James Dong } 240413aec890216948b0c364f8f92792129d0335f506James Dong } 240513aec890216948b0c364f8f92792129d0335f506James Dong } 240613aec890216948b0c364f8f92792129d0335f506James Dong 240720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 240825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 240945c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong if (isTrackMalFormed()) { 2410690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 2411f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 241245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 2413bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, -1, err); 2414be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 241513aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 241643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 2417c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong addOneStscTableEntry(1, mStszTableEntries->count()); 241858ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 24191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, mChunkSamples.size()); 24201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 242113aec890216948b0c364f8f92792129d0335f506James Dong } 242213aec890216948b0c364f8f92792129d0335f506James Dong 2423be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 2424be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 2425be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 2426c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 1) { 24278f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 242879761ab096f57c3027fad9556c2bc436672d614eJames Dong lastDurationTicks = 0; 2429be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2430be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 2431be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2432a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2433c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() <= 2) { 243479761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(1, lastDurationTicks); 2435a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (sampleCount - 1 > 0) { 243679761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); 2437a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2438a472613aec322e25891abf5c77bf3f7e3c244920James Dong } else { 243979761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount, lastDurationTicks); 2440a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2441a472613aec322e25891abf5c77bf3f7e3c244920James Dong 244243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // The last ctts box may not have been written yet, and this 244343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // is to make sure that we write out the last ctts box. 244443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) { 244543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong if (cttsSampleCount > 0) { 244643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 244743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 244843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 244943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong 2450c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 245125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 245243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 245343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong sendTrackSummary(hasMultipleTracks); 245443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 2455df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 245611f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih count, nZeroLengthFrames, mStszTableEntries->count(), trackName); 2457872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2458a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); 2459872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2460365a963142093a1cd8efdcea76b5f65096a5b115James Dong 246137187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 246237187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 246337187916a486504acaf83bea30147eb5fbf46ae5James Dong } 246437187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 2465365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 2466365a963142093a1cd8efdcea76b5f65096a5b115James Dong 246745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dongbool MPEG4Writer::Track::isTrackMalFormed() const { 2468c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { // no samples written 246929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("The number of recorded samples is 0"); 247045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return true; 247145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong } 247245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 2473c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (!mIsAudio && mStssTableEntries->count() == 0) { // no sync frames for video 247429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("There are no sync frames for video track"); 247545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return true; 247645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong } 247745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 247845c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong if (OK != checkCodecSpecificData()) { // no codec specific data 247945c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return true; 248045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong } 248145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 248245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return false; 248345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong} 248445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 248543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 248607ec01904613a0bac32caaa8444b4690998faed7James Dong 248707ec01904613a0bac32caaa8444b4690998faed7James Dong // Send track summary only if test mode is enabled. 248807ec01904613a0bac32caaa8444b4690998faed7James Dong if (!isTestModeEnabled()) { 248907ec01904613a0bac32caaa8444b4690998faed7James Dong return; 249007ec01904613a0bac32caaa8444b4690998faed7James Dong } 249107ec01904613a0bac32caaa8444b4690998faed7James Dong 249243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int trackNum = (mTrackId << 28); 249343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 249443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 249543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 249643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mIsAudio? 0: 1); 249743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 249843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 249943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 250043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mTrackDurationUs / 1000); 250143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 250243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 250343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 2504c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries->count()); 250543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 250686b7f47aa7482424cf8fd248f1315311919be3b0James Dong { 250786b7f47aa7482424cf8fd248f1315311919be3b0James Dong // The system delay time excluding the requested initial delay that 250886b7f47aa7482424cf8fd248f1315311919be3b0James Dong // is used to eliminate the recording sound. 250986b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 251086b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 251186b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 251286b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 251386b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t initialDelayUs = 251486b7f47aa7482424cf8fd248f1315311919be3b0James Dong mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 251586b7f47aa7482424cf8fd248f1315311919be3b0James Dong 251686b7f47aa7482424cf8fd248f1315311919be3b0James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 251770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 251870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong (initialDelayUs) / 1000); 251986b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 252070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 252107ec01904613a0bac32caaa8444b4690998faed7James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 252207ec01904613a0bac32caaa8444b4690998faed7James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, 252307ec01904613a0bac32caaa8444b4690998faed7James Dong mMdatSizeBytes / 1024); 252407ec01904613a0bac32caaa8444b4690998faed7James Dong 252543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (hasMultipleTracks) { 252643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 252743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 252843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs / 1000); 252970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 253070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 253170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (mStartTimestampUs != moovStartTimeUs) { 253270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 253370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 253470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 253570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong startTimeOffsetUs / 1000); 253670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 253743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 253843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong} 253943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 2540faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2541a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); 2542c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 2543215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 2544215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 2545a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); 2546bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 254793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 254893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 254993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 255093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 2551faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 2552bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong size_t trackId, int64_t timeUs, status_t err) { 2553faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 2554bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t trackNum = (trackId << 28); 2555faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2556faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 2557faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 2558faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 2559bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2560bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 2561faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2562faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2563faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2564faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2565faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 2566faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 2567bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2568bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 2569faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2570faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 2571faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 2572bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2573bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 2574faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 2575faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2576faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 2577faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2578d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2579a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); 2580e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2581d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 2582e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2583e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2584e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 2585a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); 2586e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2587e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 2588e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2589e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2590de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghuibool MPEG4Writer::isRealTimeRecording() const { 2591de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui return mIsRealTimeRecording; 2592de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui} 2593de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui 2594b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() { 2595b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong return mUse4ByteNalLength; 2596b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong} 2597b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 25981c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 25993856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("bufferChunk"); 26001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 26011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 26021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 260313aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 260420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 260520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 26063b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 2607c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 260820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 260920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2610d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2611d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 2612d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 2613d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2614690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 2615690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 2616690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2617690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2618690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2619690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2620690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 2621690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 262229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Missing codec specific data"); 2623690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2624690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2625690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 2626690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 2627690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 262829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Unexepected codec specific data found"); 2629690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2630690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2631690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2632690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 2633690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 2634690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 263620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 26373856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("%s track time scale: %d", 26381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 26398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 2640efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson uint32_t now = getMpeg4Time(); 2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("trak"); 2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeTkhdBox(now); 2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdia"); 2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMdhdBox(now); 2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeHdlrBox(); 2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("minf"); 2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSmhdBox(); 2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVmhdBox(); 2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDinfBox(); 2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStblBox(use32BitOffset); 2654b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // minf 2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mdia 2656b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // trak 2657b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stbl"); 2661b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsd"); 2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count 2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAudioFourCCBox(); 2666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVideoFourCCBox(); 2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsd 2670b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSttsBox(); 2671965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong writeCttsBox(); 2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!mIsAudio) { 2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStssBox(); 2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2675b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStszBox(); 2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStscBox(); 2677b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStcoBox(use32BitOffset); 2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stbl 2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() { 2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mp4v"); 2687b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("s263"); 2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("avc1"); 2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 269229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Unknown mime type '%s'.", mime); 2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // data ref index 2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeyWidth, &width); 2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(width); 2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(height); 2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // horiz resolution 2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // vert resolution 2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // frame count 2716c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo mOwner->writeInt8(0); // compressor string length 2717c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo mOwner->write(" ", 31); 2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x18); // depth 2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(-1); // predefined 2720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 272143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LT(23 + mCodecSpecificDataSize, 128); 2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4vEsdsBox(); 2725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeD263Box(); 2727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAvccBox(); 2729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writePaspBox(); 2732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mp4v, s263 or avc1 2733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() { 2736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *fourcc = NULL; 2740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 2741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "samr"; 2742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "sawb"; 2744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "mp4a"; 2746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 274729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Unknown mime type '%s'.", mime); 2748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(fourcc); // audio format 2752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x1); // data ref index 2755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t nChannels; 2758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(nChannels); // channel count 2760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(16); // sample size 2761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t samplerate; 2765b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeySampleRate, &samplerate); 2766b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2767b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(samplerate << 16); 2768b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2769b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4aEsdsBox(); 2770b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 2771b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2772b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDamrBox(); 2773b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2774b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2775b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2776b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2777b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() { 2778b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 2779b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 278043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mCodecSpecificDataSize, 0); 2781b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2782b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Make sure all sizes encode to a single byte. 278343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LT(mCodecSpecificDataSize + 23, 128); 2784b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2785b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2786b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 2787b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2788b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000);// ES_ID 2789b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x00); 2790b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2791b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2792b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2793b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2794b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x15); // streamType AudioStream 2795b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2796b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x03); // XXX 2797b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2798b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(96000); // max bit rate 2799b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(96000); // avg bit rate 2800b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2801b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2802b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 2803b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2804b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2805b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 2806b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 2807b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 2808b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 2809b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2810b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 2811b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2812b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 2813b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2814b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2815b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() { 2816b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 281743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mCodecSpecificDataSize, 0); 2818b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 2819b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2820b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2821b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2822b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 2823b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2824b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000); // ES_ID 2825b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x1f); 2826b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2827b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2828b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2829b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 2830b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x11); // streamType VisualStream 2831b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2832b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData[] = { 2833b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 0x77, 0x00, 2834b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x00, 0x03, 0xe8, 0x00, 2835b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x00, 0x03, 0xe8, 0x00 2836b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2837b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData, sizeof(kData)); 2838b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2839b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2840b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2841b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 2842b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2843b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2844b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 2845b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 2846b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 2847b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 2848b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2849b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 2850b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2851b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 2852b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2853b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2854efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeTkhdBox(uint32_t now) { 2855b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("tkhd"); 2856b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Flags = 7 to indicate that the track is enabled, and 2857b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // part of the presentation 2858b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x07); // version=0, flags=7 2859b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 2860b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 2861219f195159f93d627af2b243732e3f9020511a46James Dong mOwner->writeInt32(mTrackId); // track id starts with 1 2862b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 28638f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 2864b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 2865b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t tkhdDuration = 2866b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 2867b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 2868b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2869b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2870b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // layer 2871b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // alternate group 2872b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 2873b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2874b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2875b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCompositionMatrix(mRotation); // matrix 287620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2877b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2878b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2879b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2880b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2881b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 2882b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findInt32(kKeyWidth, &width); 2883b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 2884b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2885b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2886b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2887b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 2888b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2889b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // tkhd 2890b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2891b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2892b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() { 2893b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("vmhd"); 2894b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x01); // version=0, flags=1 2895b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // graphics mode 2896b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // opcolor 2897b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 2898b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 2899b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2900b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2901b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2902b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() { 2903b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("smhd"); 2904b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2905b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // balance 2906b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2907b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2908b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2909b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2910b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() { 2911b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("hdlr"); 2912b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2913b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // component type: should be mhlr 2914b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 2915b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2916b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2917b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2918b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Removing "r" for the name string just makes the string 4 byte aligned 2919b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 2920b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2921b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2922b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2923efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeMdhdBox(uint32_t now) { 2924b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t trakDurationUs = getDurationUs(); 2925b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdhd"); 2926b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2927b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 2928b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 2929b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mTimeScale); // media timescale 2930b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 2931b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mdhdDuration); // use media timescale 2932b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Language follows the three letter standard ISO-639-2/T 2933b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 'e', 'n', 'g' for "English", for instance. 2934b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Each character is packed as the difference between its ASCII value and 0x60. 2935b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // For "English", these are 00101, 01110, 00111. 2936b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // XXX: Where is the padding bit located: 0x15C7? 2937b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // language code 2938b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2939b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2940b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2941b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2942b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() { 2943b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 3gpp2 Spec AMRSampleEntry fields 2944b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("damr"); 2945b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(" "); // vendor: 4 bytes 2946b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 2947b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 2948b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // mode change period 2949b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(1); // frames per sample 2950b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2951b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2952b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2953b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() { 2954b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // The table index here refers to the sample description index 2955b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // in the sample table entries. 2956b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("url "); 2957b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2958b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // url 2959b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2960b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2961b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() { 2962b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dref"); 2963b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2964b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count (either url or urn) 2965b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeUrlBox(); 2966b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dref 2967b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2968b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2969b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() { 2970b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dinf"); 2971b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDrefBox(); 2972b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dinf 2973b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2974b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2975b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() { 2976b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 297743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GE(mCodecSpecificDataSize, 5); 2978b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2979b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Patch avcc's lengthSize field to match the number 2980b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // of bytes we use to indicate the size of a nal unit. 2981b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong uint8_t *ptr = (uint8_t *)mCodecSpecificData; 2982b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 2983b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("avcC"); 2984b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2985b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // avcC 2986b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2987b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2988b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() { 2989b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("d263"); 2990b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // vendor 2991b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 2992b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(10); // level: 10 2993b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // profile: 0 2994b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // d263 2995b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2996b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2997b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square 2998b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() { 2999b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("pasp"); 3000b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // hspacing 3001b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // vspacing 3002b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // pasp 3003b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3004b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3005000e18370baae60ffd9f25b509501dd8c26deabfJames Dongint32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { 3006a472613aec322e25891abf5c77bf3f7e3c244920James Dong int64_t trackStartTimeOffsetUs = 0; 3007b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3008b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mStartTimestampUs != moovStartTimeUs) { 300943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mStartTimestampUs, moovStartTimeUs); 3010b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3011b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 3012000e18370baae60ffd9f25b509501dd8c26deabfJames Dong return (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL; 3013000e18370baae60ffd9f25b509501dd8c26deabfJames Dong} 3014000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 3015000e18370baae60ffd9f25b509501dd8c26deabfJames Dongvoid MPEG4Writer::Track::writeSttsBox() { 3016000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mOwner->beginBox("stts"); 3017000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mOwner->writeInt32(0); // version=0, flags=0 3018c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t duration; 3019c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(mSttsTableEntries->get(duration, 1)); 3020c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong duration = htonl(duration); // Back to host byte order 3021c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); 3022c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->write(mOwner); 3023b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stts 3024b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 302520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3026965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::writeCttsBox() { 3027965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong if (mIsAudio) { // ctts is not for audio 3028965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong return; 3029965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 3030965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3031000e18370baae60ffd9f25b509501dd8c26deabfJames Dong // There is no B frame at all 3032000e18370baae60ffd9f25b509501dd8c26deabfJames Dong if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) { 3033000e18370baae60ffd9f25b509501dd8c26deabfJames Dong return; 3034000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } 3035000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 3036965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong // Do not write ctts box when there is no need to have it. 3037c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mCttsTableEntries->count() == 0) { 3038965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong return; 3039965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 3040965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3041a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", 3042c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs); 3043965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3044965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong mOwner->beginBox("ctts"); 3045000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mOwner->writeInt32(0); // version=0, flags=0 3046c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t duration; 3047c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(mCttsTableEntries->get(duration, 1)); 3048c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong duration = htonl(duration); // Back host byte order 3049c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1); 3050c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->write(mOwner); 3051965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong mOwner->endBox(); // ctts 3052965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong} 3053965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3054b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() { 3055b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stss"); 3056b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3057c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries->write(mOwner); 3058b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stss 3059b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 306025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 3061b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() { 3062b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsz"); 3063b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3064c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mOwner->writeInt32(0); 3065c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries->write(mOwner); 3066b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsz 3067b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 306820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3069b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() { 3070b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsc"); 3071b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3072c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->write(mOwner); 3073b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsc 3074b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 307520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3076b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 3077b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 3078b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3079c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (use32BitOffset) { 3080c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries->write(mOwner); 3081c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } else { 3082c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries->write(mOwner); 3083b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 3084b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stco or co64 308520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 308620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 308707b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() { 308807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("udta"); 308907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeGeoDataBox(); 309007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 309107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 309207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 309307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 309407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 309507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 309607b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() { 309707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("\xA9xyz"); 309807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong /* 309907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * For historical reasons, any user data start 310007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * with "\0xA9", must be followed by its assoicated 310107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * language code. 3102432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong * 0x0012: text string length 3103432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong * 0x15c7: lang (locale) code: en 310407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 310507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt32(0x001215c7); 310607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLatitude(mLatitudex10000); 310707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLongitude(mLongitudex10000); 310807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt8(0x2F); 310907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 311007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 311107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 311220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 3113