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> 32e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang#include <media/stagefright/foundation/AMessage.h> 3358fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar#include <media/stagefright/foundation/ColorUtils.h> 3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 3520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 3718291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 3803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 41d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h> 4207ec01904613a0bac32caaa8444b4690998faed7James Dong#include <cutils/properties.h> 4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 459aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim#include "include/HevcUtils.h" 46dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn 47dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn#ifndef __predict_false 48dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn#define __predict_false(exp) __builtin_expect((exp) != 0, 0) 49dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn#endif 50dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn 5111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih#define WARN_UNLESS(condition, message, ...) \ 52dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn( (__predict_false(condition)) ? false : ({ \ 5311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih ALOGW("Condition %s failed " message, #condition, ##__VA_ARGS__); \ 5411f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih true; \ 5511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih})) 5611f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 5720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 5820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5977e8ae9967a078770416619e99ddb5b010def312James Dongstatic const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; 601f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachadstatic const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32 611f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad // filesystem file size 621f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad // used by most SD cards 633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 6570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongstatic const int64_t kInitialDelayTimeUs = 700000LL; 665b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong 677c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhangstatic const char kMetaKey_Version[] = "com.android.version"; 683b0da19c78f6a61ed343a07f2448b94faafe4c02Lajos Molnar#ifdef SHOW_MODEL_BUILD 693b0da19c78f6a61ed343a07f2448b94faafe4c02Lajos Molnarstatic const char kMetaKey_Model[] = "com.android.model"; 707c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhangstatic const char kMetaKey_Build[] = "com.android.build"; 713b0da19c78f6a61ed343a07f2448b94faafe4c02Lajos Molnar#endif 727c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhangstatic const char kMetaKey_CaptureFps[] = "com.android.capture.fps"; 737c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang 749aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kimstatic const uint8_t kMandatoryHevcNalUnitTypes[3] = { 759aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypeVps, 769aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypeSps, 779aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypePps, 789aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim}; 799aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kimstatic const uint8_t kHevcNalUnitTypes[5] = { 809aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypeVps, 819aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypeSps, 829aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypePps, 839aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypePrefixSei, 849aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim kHevcNalUnitTypeSuffixSei, 859aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim}; 867c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang/* uncomment to include model and build in meta */ 877c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang//#define SHOW_MODEL_BUILD 1 887c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang 8920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 9020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 91b2487f03f12dcafdb801fc0007c8df8412397f44Marco Nelissen Track(MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId); 928f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 9320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 9420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 9637187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 9737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 9825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1003b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 101d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 102b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeTrackHeader(bool use32BitOffset = true); 1031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 1041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 1059aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim bool isHevc() const { return mIsHevc; } 1061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 1071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 108c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong void addChunkOffset(off64_t offset); 10970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int32_t getTrackId() const { return mTrackId; } 110dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong status_t dump(int fd, const Vector<String16>& args) const; 1118b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan static const char *getFourCCForMime(const char *mime); 11220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 11320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 114000e18370baae60ffd9f25b509501dd8c26deabfJames Dong enum { 115000e18370baae60ffd9f25b509501dd8c26deabfJames Dong kMaxCttsOffsetTimeUs = 1000000LL, // 1 second 1168c460498c028888c533ab442be12b6d4b669b965James Dong kSampleArraySize = 1000, 117000e18370baae60ffd9f25b509501dd8c26deabfJames Dong }; 118000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 119c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // A helper class to handle faster write box with table entries 120c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong template<class TYPE> 121c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong struct ListTableEntries { 122c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries(uint32_t elementCapacity, uint32_t entryCapacity) 123c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong : mElementCapacity(elementCapacity), 124c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mEntryCapacity(entryCapacity), 125c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mTotalNumTableEntries(0), 126c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mNumValuesInCurrEntry(0), 127c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCurrTableEntriesElement(NULL) { 128c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_GT(mElementCapacity, 0); 129c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_GT(mEntryCapacity, 0); 1302177f21c1ae5bf5cb8c1113a1adbe1fd7db34206Wei Jia // Ensure no integer overflow on allocation in add(). 1312177f21c1ae5bf5cb8c1113a1adbe1fd7db34206Wei Jia CHECK_LT(mEntryCapacity, UINT32_MAX / mElementCapacity); 132c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 133c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 134c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Free the allocated memory. 135c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ~ListTableEntries() { 136c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong while (!mTableEntryList.empty()) { 137c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong typename List<TYPE *>::iterator it = mTableEntryList.begin(); 138c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete[] (*it); 139c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mTableEntryList.erase(it); 140c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 141c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 142c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 143c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Replace the value at the given position by the given value. 144c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // There must be an existing value at the given position. 145c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg value must be in network byte order 146c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg pos location the value must be in. 147c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong void set(const TYPE& value, uint32_t pos) { 14825f0d7ba1987de61c75f8c68b19de48e0ad9736cJames Dong CHECK_LT(pos, mTotalNumTableEntries * mEntryCapacity); 149c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 150c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong typename List<TYPE *>::iterator it = mTableEntryList.begin(); 151c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity)); 152c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong while (it != mTableEntryList.end() && iterations > 0) { 153c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++it; 154c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong --iterations; 155c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 156c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(it != mTableEntryList.end()); 157c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_EQ(iterations, 0); 158c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 159c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong (*it)[(pos % (mElementCapacity * mEntryCapacity))] = value; 160c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 161c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 162c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Get the value at the given position by the given value. 163c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg value the retrieved value at the position in network byte order. 164c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg pos location the value must be in. 165c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @return true if a value is found. 166c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong bool get(TYPE& value, uint32_t pos) const { 16725f0d7ba1987de61c75f8c68b19de48e0ad9736cJames Dong if (pos >= mTotalNumTableEntries * mEntryCapacity) { 168c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong return false; 169c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 170c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 171c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong typename List<TYPE *>::iterator it = mTableEntryList.begin(); 172c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity)); 173c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong while (it != mTableEntryList.end() && iterations > 0) { 174c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++it; 175c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong --iterations; 176c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 177c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(it != mTableEntryList.end()); 178c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_EQ(iterations, 0); 179c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 180c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong value = (*it)[(pos % (mElementCapacity * mEntryCapacity))]; 181c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong return true; 182c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 183c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 184c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Store a single value. 185c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg value must be in network byte order. 186c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong void add(const TYPE& value) { 187c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_LT(mNumValuesInCurrEntry, mElementCapacity); 188c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t nEntries = mTotalNumTableEntries % mElementCapacity; 189c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t nValues = mNumValuesInCurrEntry % mEntryCapacity; 190c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (nEntries == 0 && nValues == 0) { 191c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCurrTableEntriesElement = new TYPE[mEntryCapacity * mElementCapacity]; 192c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(mCurrTableEntriesElement != NULL); 193c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mTableEntryList.push_back(mCurrTableEntriesElement); 194c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 195c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 196c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t pos = nEntries * mEntryCapacity + nValues; 197c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCurrTableEntriesElement[pos] = value; 198c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 199c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++mNumValuesInCurrEntry; 200c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if ((mNumValuesInCurrEntry % mEntryCapacity) == 0) { 201c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ++mTotalNumTableEntries; 202c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mNumValuesInCurrEntry = 0; 203c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 204c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 205c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 206c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Write out the table entries: 207c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // 1. the number of entries goes first 208c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // 2. followed by the values in the table enties in order 209c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // @arg writer the writer to actual write to the storage 210c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong void write(MPEG4Writer *writer) const { 211c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_EQ(mNumValuesInCurrEntry % mEntryCapacity, 0); 212c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t nEntries = mTotalNumTableEntries; 213c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong writer->writeInt32(nEntries); 214c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong for (typename List<TYPE *>::iterator it = mTableEntryList.begin(); 215c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong it != mTableEntryList.end(); ++it) { 216c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK_GT(nEntries, 0); 217c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (nEntries >= mElementCapacity) { 218c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong writer->write(*it, sizeof(TYPE) * mEntryCapacity, mElementCapacity); 219c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong nEntries -= mElementCapacity; 220c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } else { 221c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong writer->write(*it, sizeof(TYPE) * mEntryCapacity, nEntries); 222c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong break; 223c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 224c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 225c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 226c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 227c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong // Return the number of entries in the table. 228c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t count() const { return mTotalNumTableEntries; } 229c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 230c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong private: 231c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mElementCapacity; // # entries in an element 232c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mEntryCapacity; // # of values in each entry 233c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mTotalNumTableEntries; 234c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t mNumValuesInCurrEntry; // up to mEntryCapacity 235c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong TYPE *mCurrTableEntriesElement; 236c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mutable List<TYPE *> mTableEntryList; 237c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 238c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries); 239c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong }; 240c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 241c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 242c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 24320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 24420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 245b2487f03f12dcafdb801fc0007c8df8412397f44Marco Nelissen sp<IMediaSource> mSource; 24620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 247a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 248a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 249eaae38445a340c4857c1c5569475879a728e63b7James Dong volatile bool mStarted; 2501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 2519aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim bool mIsHevc; 2521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 2531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 254bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t mTrackId; 255c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 25643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t mMaxChunkDurationUs; 257e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 258d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 2591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t mMdatSizeBytes; 2608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 26120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 26220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 26320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 264be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 26513aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 2661f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 267c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong bool mSamplesHaveSameSize; 268c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStszTableEntries; 269be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 270c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStcoTableEntries; 271c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<off64_t> *mCo64TableEntries; 272c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStscTableEntries; 273c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mStssTableEntries; 274c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mSttsTableEntries; 275c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ListTableEntries<uint32_t> *mCttsTableEntries; 276965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 277000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t mMinCttsOffsetTimeUs; 278000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t mMaxCttsOffsetTimeUs; 279965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 2803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 2813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 2823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 2833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 2843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 2853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 2863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 2873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 2883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 2893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 2903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 2913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 2923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 2933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 29420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 29520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 296548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 29793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 29820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 29925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 3003c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 30170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mStartTimeRealUs; 30270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mFirstSampleTimeRealUs; 30393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 30493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 30525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 306872a481558350634a3fd5cb67939de288af00ecbJames Dong // Update the audio track's drift information. 307872a481558350634a3fd5cb67939de288af00ecbJames Dong void updateDriftTime(const sp<MetaData>& meta); 308872a481558350634a3fd5cb67939de288af00ecbJames Dong 309000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int32_t getStartTimeOffsetScaledTime() const; 310000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 31120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 31237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 31320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 3153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 3163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 3179aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim status_t copyCodecSpecificData(const uint8_t *data, size_t size, size_t minLength = 0); 3189aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 319b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size); 320b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size); 321b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size); 322215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 3239aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim status_t makeHEVCCodecSpecificData(const uint8_t *data, size_t size); 3249aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim status_t copyHEVCCodecSpecificData(const uint8_t *data, size_t size); 3259aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim status_t parseHEVCCodecSpecificData( 3269aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const uint8_t *data, size_t size, HevcParameterSets ¶mSets); 3279aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 328215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 329faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 33093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 33103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 33219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 33319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 334c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 335c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 336c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 337c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 338c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 339c059860c73678a202bfa33062723e8f82fb779d9James Dong 340690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 341690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 34213f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t mRotation; 343690f546b0ee548dbfe997df36418e5302ec2d786James Dong 3441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void updateTrackSizeEstimate(); 3451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStscTableEntry(size_t chunkId, size_t sampleId); 3461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStssTableEntry(size_t sampleId); 34779761ab096f57c3027fad9556c2bc436672d614eJames Dong 34879761ab096f57c3027fad9556c2bc436672d614eJames Dong // Duration is time scale based 34979761ab096f57c3027fad9556c2bc436672d614eJames Dong void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur); 350965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur); 35145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 35245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong bool isTrackMalFormed() const; 35343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong void sendTrackSummary(bool hasMultipleTracks); 3541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 355b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Write the boxes 356b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStcoBox(bool use32BitOffset); 357b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStscBox(); 358b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStszBox(); 359b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStssBox(); 360b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSttsBox(); 361965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong void writeCttsBox(); 362b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeD263Box(); 363b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writePaspBox(); 364b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAvccBox(); 3659aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim void writeHvccBox(); 366b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeUrlBox(); 367b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDrefBox(); 368b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDinfBox(); 369b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDamrBox(); 370efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson void writeMdhdBox(uint32_t now); 371b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSmhdBox(); 372b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVmhdBox(); 373b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeHdlrBox(); 374efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson void writeTkhdBox(uint32_t now); 37558fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar void writeColrBox(); 376b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4aEsdsBox(); 377b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4vEsdsBox(); 378b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAudioFourCCBox(); 379b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVideoFourCCBox(); 380b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStblBox(bool use32BitOffset); 381b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 38220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 38320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 38420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 38520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 38630ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 387674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(dup(fd)), 388674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(mFd < 0? NO_INIT: OK), 389de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mIsRealTimeRecording(true), 390b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 3911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 392a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 393a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 394a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 395411ba422e3635d534928ffd81abf54f4f291c739James Dong mWriterThreadStarted(false), 39630ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 39713aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 398e502b443ce9d229d1e9108834887c6e520948816Chong Zhang mMoovBoxBuffer(NULL), 399e502b443ce9d229d1e9108834887c6e520948816Chong Zhang mMoovBoxBufferOffset(0), 400e502b443ce9d229d1e9108834887c6e520948816Chong Zhang mWriteMoovBoxToMemory(false), 401e502b443ce9d229d1e9108834887c6e520948816Chong Zhang mFreeBoxOffset(0), 402e502b443ce9d229d1e9108834887c6e520948816Chong Zhang mStreamableFile(false), 4037837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 4047c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMoovExtraSize(0), 40507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mInterleaveDurationUs(1000000), 406e502b443ce9d229d1e9108834887c6e520948816Chong Zhang mTimeScale(-1), 407e502b443ce9d229d1e9108834887c6e520948816Chong Zhang mStartTimestampUs(-1ll), 40807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000(0), 40907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000(0), 41086b7f47aa7482424cf8fd248f1315311919be3b0James Dong mAreGeoTagsAvailable(false), 411ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar mStartTimeOffsetMs(-1), 412ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar mMetaKeys(new AMessage()) { 4137c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang addDeviceMeta(); 4142aa74dc097fe860abc84769abf2b6e0962718471Robert Shih 4152aa74dc097fe860abc84769abf2b6e0962718471Robert Shih // Verify mFd is seekable 4162aa74dc097fe860abc84769abf2b6e0962718471Robert Shih off64_t off = lseek64(mFd, 0, SEEK_SET); 4172aa74dc097fe860abc84769abf2b6e0962718471Robert Shih if (off < 0) { 4182aa74dc097fe860abc84769abf2b6e0962718471Robert Shih ALOGE("cannot seek mFd: %s (%d)", strerror(errno), errno); 4192aa74dc097fe860abc84769abf2b6e0962718471Robert Shih release(); 4202aa74dc097fe860abc84769abf2b6e0962718471Robert Shih } 42130ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 42230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 42320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 4248bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dong reset(); 42520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4261f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong while (!mTracks.empty()) { 4271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong List<Track *>::iterator it = mTracks.begin(); 42820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 4291f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong (*it) = NULL; 4301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mTracks.erase(it); 43120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 43220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 43320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 43420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 435dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 436dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 437dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 438dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 439dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 440dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 441dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 442dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 443dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 444dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 445dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 446dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 447dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 448dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 449dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 450dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 451dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 452dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 45384333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber int fd, const Vector<String16>& /* args */) const { 454dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 455dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 456dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 457dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 458dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 459dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 460dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 461dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 462c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong snprintf(buffer, SIZE, " frames encoded : %d\n", mStszTableEntries->count()); 46313210f3346462a86ce9fe3af72a0c200dba84e27James Dong result.append(buffer); 464377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT snprintf(buffer, SIZE, " duration encoded : %" PRId64 " us\n", mTrackDurationUs); 46513210f3346462a86ce9fe3af72a0c200dba84e27James Dong result.append(buffer); 466dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 467dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 468dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 469dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 4708b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan// static 4718b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavanconst char *MPEG4Writer::Track::getFourCCForMime(const char *mime) { 4728b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan if (mime == NULL) { 4738b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return NULL; 4748b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } 4758b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan if (!strncasecmp(mime, "audio/", 6)) { 4768b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 4778b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return "samr"; 4788b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 4798b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return "sawb"; 4808b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 4818b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return "mp4a"; 4828b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } 4838b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } else if (!strncasecmp(mime, "video/", 6)) { 4848b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 4858b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return "mp4v"; 4868b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 4878b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return "s263"; 4888b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 4898b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return "avc1"; 4909aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { 4919aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return "hvc1"; 4928b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } 4938b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } else { 4948b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan ALOGE("Track (%s) other than video or audio is not supported", mime); 4958b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan } 4968b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan return NULL; 4978b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan} 4988b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan 499b2487f03f12dcafdb801fc0007c8df8412397f44Marco Nelissenstatus_t MPEG4Writer::addSource(const sp<IMediaSource> &source) { 500bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Mutex::Autolock l(mLock); 501bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong if (mStarted) { 50229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Attempt to add source AFTER recording is started"); 503bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong return UNKNOWN_ERROR; 504bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong } 505acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 506acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // At most 2 tracks can be supported. 507acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong if (mTracks.size() >= 2) { 508a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGE("Too many tracks (%zu) to add", mTracks.size()); 509acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return ERROR_UNSUPPORTED; 510acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 511acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 512acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong CHECK(source.get() != NULL); 513acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 514acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong const char *mime; 515acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong source->getFormat()->findCString(kKeyMIMEType, &mime); 516acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong bool isAudio = !strncasecmp(mime, "audio/", 6); 5178b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan if (Track::getFourCCForMime(mime) == NULL) { 5188b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan ALOGE("Unsupported mime '%s'", mime); 519acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return ERROR_UNSUPPORTED; 520acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 521acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 522acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // At this point, we know the track to be added is either 523acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // video or audio. Thus, we only need to check whether it 524acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // is an audio track or not (if it is not, then it must be 525acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // a video track). 526acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 527acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // No more than one video or one audio track is supported. 528acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong for (List<Track*>::iterator it = mTracks.begin(); 529acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong it != mTracks.end(); ++it) { 530acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong if ((*it)->isAudio() == isAudio) { 531acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong ALOGE("%s track already exists", isAudio? "Audio": "Video"); 532acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return ERROR_UNSUPPORTED; 533acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 534acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 535acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 536acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // This is the first track of either audio or video. 537acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong // Go ahead to add the track. 538219f195159f93d627af2b243732e3f9020511a46James Dong Track *track = new Track(this, source, 1 + mTracks.size()); 53920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 5402dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 5412dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 54220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 54320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 54493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 545acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong if (mTracks.empty()) { 546acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong ALOGE("No source added"); 547acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong return INVALID_OPERATION; 548acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong } 549acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong 550a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 551a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 55293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 553a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 554a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 555a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 556a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 557a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 558a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 559a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 560a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 561a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 562a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 563a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 564a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 565a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 5667c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhangvoid MPEG4Writer::addDeviceMeta() { 5677c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang // add device info and estimate space in 'moov' 5687c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang char val[PROPERTY_VALUE_MAX]; 5697c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang size_t n; 5707c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang // meta size is estimated by adding up the following: 5717c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang // - meta header structures, which occur only once (total 66 bytes) 5727c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang // - size for each key, which consists of a fixed header (32 bytes), 5737c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang // plus key length and data length. 5747c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMoovExtraSize += 66; 5757c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang if (property_get("ro.build.version.release", val, NULL) 5767c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang && (n = strlen(val)) > 0) { 5777c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMetaKeys->setString(kMetaKey_Version, val, n + 1); 5787c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMoovExtraSize += sizeof(kMetaKey_Version) + n + 32; 5797c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang } 5807c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang#ifdef SHOW_MODEL_BUILD 5817c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang if (property_get("ro.product.model", val, NULL) 5827c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang && (n = strlen(val)) > 0) { 5837c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMetaKeys->setString(kMetaKey_Model, val, n + 1); 5847c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMoovExtraSize += sizeof(kMetaKey_Model) + n + 32; 5857c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang } 5867c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang if (property_get("ro.build.display.id", val, NULL) 5877c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang && (n = strlen(val)) > 0) { 5887c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMetaKeys->setString(kMetaKey_Build, val, n + 1); 5897c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMoovExtraSize += sizeof(kMetaKey_Build) + n + 32; 5907c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang } 5917c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang#endif 5927c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang} 5937c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang 5942dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 5952dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 5962dec2b5be2056c6d9428897dc672185872d30d17James Dong // 5972dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 5982dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 5992dec2b5be2056c6d9428897dc672185872d30d17James Dong 60078a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 6012dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 60278a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 3 6032dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 6042dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 6052dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 6062dec2b5be2056c6d9428897dc672185872d30d17James Dong 6072dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 6082dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 6092dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 61078a1a286f736888ae7af8860b2c424af0d978848James Dong static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 6112dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 6122dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 6132dec2b5be2056c6d9428897dc672185872d30d17James Dong 61478a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file size limit is set 615a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 61678a1a286f736888ae7af8860b2c424af0d978848James Dong size = mMaxFileSizeLimitBytes * 6 / 1000; 61778a1a286f736888ae7af8860b2c424af0d978848James Dong } 61878a1a286f736888ae7af8860b2c424af0d978848James Dong 61978a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file duration limit is set 62078a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileDurationLimitUs != 0) { 62178a1a286f736888ae7af8860b2c424af0d978848James Dong if (bitRate > 0) { 62278a1a286f736888ae7af8860b2c424af0d978848James Dong int64_t size2 = 62378a1a286f736888ae7af8860b2c424af0d978848James Dong ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 62478a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 62578a1a286f736888ae7af8860b2c424af0d978848James Dong // When both file size and duration limits are set, 62678a1a286f736888ae7af8860b2c424af0d978848James Dong // we use the smaller limit of the two. 62778a1a286f736888ae7af8860b2c424af0d978848James Dong if (size > size2) { 62878a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 62978a1a286f736888ae7af8860b2c424af0d978848James Dong } 63078a1a286f736888ae7af8860b2c424af0d978848James Dong } else { 63178a1a286f736888ae7af8860b2c424af0d978848James Dong // Only max file duration limit is set 63278a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 63378a1a286f736888ae7af8860b2c424af0d978848James Dong } 6342dec2b5be2056c6d9428897dc672185872d30d17James Dong } 6352dec2b5be2056c6d9428897dc672185872d30d17James Dong } 63678a1a286f736888ae7af8860b2c424af0d978848James Dong 6372dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 6382dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 6392dec2b5be2056c6d9428897dc672185872d30d17James Dong } 6402dec2b5be2056c6d9428897dc672185872d30d17James Dong 6412dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 6422dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 6432dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 6442dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 6452dec2b5be2056c6d9428897dc672185872d30d17James Dong } 6462dec2b5be2056c6d9428897dc672185872d30d17James Dong 6477c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang // Account for the extra stuff (Geo, meta keys, etc.) 6487c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang size += mMoovExtraSize; 6497c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang 650a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the" 651a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn " estimated moov size %" PRId64 " bytes", 6522dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 6532dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 6542dec2b5be2056c6d9428897dc672185872d30d17James Dong} 6552dec2b5be2056c6d9428897dc672185872d30d17James Dong 6562dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 657674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 65825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 66020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 661a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong /* 662a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * Check mMaxFileSizeLimitBytes at the beginning 663a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * since mMaxFileSizeLimitBytes may be implicitly 664a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * changed later for 32-bit file offset even if 665a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * user does not ask to set it explicitly. 666a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong */ 667a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0) { 668a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested = true; 669a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong } 670a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong 6712dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 6722dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 6732dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 6742dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 6752dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 6762dec2b5be2056c6d9428897dc672185872d30d17James Dong } 6772dec2b5be2056c6d9428897dc672185872d30d17James Dong 6781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mUse32BitOffset) { 6791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // Implicit 32 bit file size limit 6801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes == 0) { 6811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 6821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 6831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 6841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // If file size is set to be larger than the 32 bit file 6851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // size limit, treat it as an error. 6861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 687a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. " 688a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn "It is changed to %" PRId64 " bytes", 689d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes, kMax32BitFileSize); 690d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 6911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 6921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 6931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 694b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong int32_t use2ByteNalLength; 695b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (param && 696b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 697b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong use2ByteNalLength) { 698b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength = false; 6992dec2b5be2056c6d9428897dc672185872d30d17James Dong } 7002dec2b5be2056c6d9428897dc672185872d30d17James Dong 701de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui int32_t isRealTimeRecording; 702de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) { 703de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mIsRealTimeRecording = isRealTimeRecording; 704de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 705de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui 706065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 70793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 708a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 709a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 710a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 71193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 712a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 713a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 714a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 715a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 7168f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 7178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 7188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 7198f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 72043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mTimeScale, 0); 7213856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("movie time scale: %d", mTimeScale); 7228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 72377e8ae9967a078770416619e99ddb5b010def312James Dong /* 72477e8ae9967a078770416619e99ddb5b010def312James Dong * When the requested file size limit is small, the priority 72577e8ae9967a078770416619e99ddb5b010def312James Dong * is to meet the file size limit requirement, rather than 7267b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * to make the file streamable. mStreamableFile does not tell 7277b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * whether the actual recorded file is streamable or not. 72877e8ae9967a078770416619e99ddb5b010def312James Dong */ 72977e8ae9967a078770416619e99ddb5b010def312James Dong mStreamableFile = 73077e8ae9967a078770416619e99ddb5b010def312James Dong (mMaxFileSizeLimitBytes != 0 && 73177e8ae9967a078770416619e99ddb5b010def312James Dong mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes); 73277e8ae9967a078770416619e99ddb5b010def312James Dong 7337b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong /* 7347b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * mWriteMoovBoxToMemory is true if the amount of data in moov box is 7357b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * smaller than the reserved free space at the beginning of a file, AND 7367b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * when the content of moov box is constructed. Note that video/audio 7377b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * frame data is always written to the file but not in the memory. 7387b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 7397b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * Before stop()/reset() is called, mWriteMoovBoxToMemory is always 7407b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * false. When reset() is called at the end of a recording session, 7417b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * Moov box needs to be constructed. 7427b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 7437b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory 7447b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * to set to mStreamableFile so that if 7457b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * the file is intended to be streamable, it is set to true; 7467b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * otherwise, it is set to false. When the value is set to false, 7477b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * all the content of the moov box is written immediately to 7487b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * the end of the file. When the value is set to true, all the 7497b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * content of the moov box is written to an in-memory cache, 7507b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * mMoovBoxBuffer, util the following condition happens. Note 7517b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * that the size of the in-memory cache is the same as the 7527b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * reserved free space at the beginning of the file. 7537b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 7547b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 2) While the data of the moov box is written to an in-memory 7557b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * cache, the data size is checked against the reserved space. 7567b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * If the data size surpasses the reserved space, subsequent moov 7577b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * data could no longer be hold in the in-memory cache. This also 7587b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * indicates that the reserved space was too small. At this point, 7597b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * _all_ moov data must be written to the end of the file. 7607b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * mWriteMoovBoxToMemory must be set to false to direct the write 7617b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * to the file. 7627b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 7637b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * 3) If the data size in moov box is smaller than the reserved 7647b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * space after moov box is completely constructed, the in-memory 7657b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * cache copy of the moov box is written to the reserved free 7667b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * space. Thus, immediately after the moov is completedly 7677b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong * constructed, mWriteMoovBoxToMemory is always set to false. 7687b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong */ 7697b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mWriteMoovBoxToMemory = false; 7707837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 7717837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 7727837c17063a4c50bc856ba59418516fdab731de7James Dong 773b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFtypBox(param); 77420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7757837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 77620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7777837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 7782dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 7792dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 7802dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 7812dec2b5be2056c6d9428897dc672185872d30d17James Dong } 7822dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 7837837c17063a4c50bc856ba59418516fdab731de7James Dong } 78443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GE(mEstimatedMoovBoxSize, 8); 78577e8ae9967a078770416619e99ddb5b010def312James Dong if (mStreamableFile) { 78677e8ae9967a078770416619e99ddb5b010def312James Dong // Reserve a 'free' box only for streamable file 78777e8ae9967a078770416619e99ddb5b010def312James Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 78877e8ae9967a078770416619e99ddb5b010def312James Dong writeInt32(mEstimatedMoovBoxSize); 78977e8ae9967a078770416619e99ddb5b010def312James Dong write("free", 4); 79077e8ae9967a078770416619e99ddb5b010def312James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 79177e8ae9967a078770416619e99ddb5b010def312James Dong } else { 79277e8ae9967a078770416619e99ddb5b010def312James Dong mMdatOffset = mOffset; 79377e8ae9967a078770416619e99ddb5b010def312James Dong } 7947837c17063a4c50bc856ba59418516fdab731de7James Dong 7957837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 796c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 7971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 7981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 7991acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 8001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 8011acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 8021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 8041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 8051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 8061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 809a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 810a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 81120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 8121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 813a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 81425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 81520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 81620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const { 8181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong return mUse32BitOffset; 8191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 8201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 82137187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 822674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 82337187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 824a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 825a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 82637187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 827a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 828a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 82937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 83037187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 83137187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 83237187916a486504acaf83bea30147eb5fbf46ae5James Dong } 833a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 83437187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 835a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 836a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 8371c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 838b8a805261bf0282e992d3608035e47d05a898710Steve Block ALOGD("Stopping writer thread"); 839411ba422e3635d534928ffd81abf54f4f291c739James Dong if (!mWriterThreadStarted) { 840411ba422e3635d534928ffd81abf54f4f291c739James Dong return; 841411ba422e3635d534928ffd81abf54f4f291c739James Dong } 8421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 8441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 8451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 8471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 8481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 8511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 852411ba422e3635d534928ffd81abf54f4f291c739James Dong mWriterThreadStarted = false; 853b8a805261bf0282e992d3608035e47d05a898710Steve Block ALOGD("Writer thread stopped"); 8541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 8551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 85613f6284305e4b27395a23db7882d670bdb1bcae1James Dong/* 85713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix: 85813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a b u | 85913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c d v | 86013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x y w | 86113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * 86213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following 86313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w}, 86413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while 86513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format. 86613f6284305e4b27395a23db7882d670bdb1bcae1James Dong */ 86713f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) { 8683856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("writeCompositionMatrix"); 86913f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t a = 0x00010000; 87013f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t b = 0; 87113f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t c = 0; 87213f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t d = 0x00010000; 87313f6284305e4b27395a23db7882d670bdb1bcae1James Dong switch (degrees) { 87413f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 0: 87513f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 87613f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 90: 87713f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 87813f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0x00010000; 87913f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0xFFFF0000; 88013f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 88113f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 88213f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 180: 88313f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0xFFFF0000; 88413f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0xFFFF0000; 88513f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 88613f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 270: 88713f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 88813f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0xFFFF0000; 88913f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0x00010000; 89013f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 89113f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 89213f6284305e4b27395a23db7882d670bdb1bcae1James Dong default: 89313f6284305e4b27395a23db7882d670bdb1bcae1James Dong CHECK(!"Should never reach this unknown rotation"); 89413f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 89513f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 89613f6284305e4b27395a23db7882d670bdb1bcae1James Dong 89713f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(a); // a 89813f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(b); // b 89913f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // u 90013f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(c); // c 90113f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(d); // d 90213f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // v 90313f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // x 90413f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // y 90513f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0x40000000); // w 90613f6284305e4b27395a23db7882d670bdb1bcae1James Dong} 90713f6284305e4b27395a23db7882d670bdb1bcae1James Dong 908411ba422e3635d534928ffd81abf54f4f291c739James Dongvoid MPEG4Writer::release() { 909411ba422e3635d534928ffd81abf54f4f291c739James Dong close(mFd); 910411ba422e3635d534928ffd81abf54f4f291c739James Dong mFd = -1; 911411ba422e3635d534928ffd81abf54f4f291c739James Dong mInitCheck = NO_INIT; 912411ba422e3635d534928ffd81abf54f4f291c739James Dong mStarted = false; 9134c845fde3d60ad93984879f69b164e35536e080dSuresh Choudhary free(mMoovBoxBuffer); 9144c845fde3d60ad93984879f69b164e35536e080dSuresh Choudhary mMoovBoxBuffer = NULL; 915411ba422e3635d534928ffd81abf54f4f291c739James Dong} 91613f6284305e4b27395a23db7882d670bdb1bcae1James Dong 9178bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dongstatus_t MPEG4Writer::reset() { 918674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 91937187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 920411ba422e3635d534928ffd81abf54f4f291c739James Dong } else { 921411ba422e3635d534928ffd81abf54f4f291c739James Dong if (!mWriterThreadStarted || 922411ba422e3635d534928ffd81abf54f4f291c739James Dong !mStarted) { 923411ba422e3635d534928ffd81abf54f4f291c739James Dong if (mWriterThreadStarted) { 924411ba422e3635d534928ffd81abf54f4f291c739James Dong stopWriterThread(); 925411ba422e3635d534928ffd81abf54f4f291c739James Dong } 926411ba422e3635d534928ffd81abf54f4f291c739James Dong release(); 927411ba422e3635d534928ffd81abf54f4f291c739James Dong return OK; 928411ba422e3635d534928ffd81abf54f4f291c739James Dong } 92920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 93020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 93137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 9328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 93365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong int64_t minDurationUs = 0x7fffffffffffffffLL; 93420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 93520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 93637187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 93737187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 93837187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 93937187916a486504acaf83bea30147eb5fbf46ae5James Dong } 94020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9418f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 9428f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 9438f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 94420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 94565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (durationUs < minDurationUs) { 94665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs = durationUs; 94765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 94865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 94965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong 95065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (mTracks.size() > 1) { 951a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", 95265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs, maxDurationUs); 95320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 95420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 9567837c17063a4c50bc856ba59418516fdab731de7James Dong 95737187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 95837187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 959411ba422e3635d534928ffd81abf54f4f291c739James Dong release(); 96037187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 96137187916a486504acaf83bea30147eb5fbf46ae5James Dong } 96237187916a486504acaf83bea30147eb5fbf46ae5James Dong 96320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 9641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 965c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 9661f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset)); 967c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 4); 9681acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 969c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset + 8, SEEK_SET); 9701f1f2b1678fd0d038dfc501252dd2b65ecf10caeRachad uint64_t size = mOffset - mMdatOffset; 9711acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 972c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 8); 9731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 974c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 97520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9767b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // Construct moov box now 9777837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 9787b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mWriteMoovBoxToMemory = mStreamableFile; 9797b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong if (mWriteMoovBoxToMemory) { 9807b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // There is no need to allocate in-memory cache 9817b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // for moov box if the file is not streamable. 9827b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 9837b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 9847b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong CHECK(mMoovBoxBuffer != NULL); 9857b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong } 986b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMoovBox(maxDurationUs); 98720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9887b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // mWriteMoovBoxToMemory could be set to false in 9897b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // MPEG4Writer::write() method 9907b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong if (mWriteMoovBoxToMemory) { 9917b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong mWriteMoovBoxToMemory = false; 9927b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // Content of the moov box is saved in the cache, and the in-memory 9937b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // moov box needs to be written to the file in a single shot. 9947b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 99543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize); 9967837c17063a4c50bc856ba59418516fdab731de7James Dong 9977837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 998c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 9997837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 1000674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 10017837c17063a4c50bc856ba59418516fdab731de7James Dong 10027837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 1003c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 10047837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 10057837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 10067b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong } else { 10077b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong ALOGI("The mp4 file will not be streamable."); 10087b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong } 10097837c17063a4c50bc856ba59418516fdab731de7James Dong 10107b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // Free in-memory cache for moov box 10117b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong if (mMoovBoxBuffer != NULL) { 10127837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 10137837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 10147837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 10157837c17063a4c50bc856ba59418516fdab731de7James Dong } 10167837c17063a4c50bc856ba59418516fdab731de7James Dong 10170c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 101820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1019411ba422e3635d534928ffd81abf54f4f291c739James Dong release(); 102037187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 102120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 102220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1023efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonuint32_t MPEG4Writer::getMpeg4Time() { 1024b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong time_t now = time(NULL); 1025efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson // MP4 file uses time counting seconds since midnight, Jan. 1, 1904 1026efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson // while time function returns Unix epoch values which starts 1027efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson // at 1970-01-01. Lets add the number of seconds between them 10282b3b672cf57657640ece98810cb34ae2bfa91e14Marco Nelissen static const uint32_t delta = (66 * 365 + 17) * (24 * 60 * 60); 10292b3b672cf57657640ece98810cb34ae2bfa91e14Marco Nelissen if (now < 0 || uint32_t(now) > UINT32_MAX - delta) { 10302b3b672cf57657640ece98810cb34ae2bfa91e14Marco Nelissen return 0; 10312b3b672cf57657640ece98810cb34ae2bfa91e14Marco Nelissen } 10322b3b672cf57657640ece98810cb34ae2bfa91e14Marco Nelissen uint32_t mpeg4Time = uint32_t(now) + delta; 1033efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson return mpeg4Time; 1034efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson} 1035efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson 1036efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) { 1037efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson uint32_t now = getMpeg4Time(); 1038b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("mvhd"); 1039b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // version=0, flags=0 1040b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // creation time 1041b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // modification time 1042b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTimeScale); // mvhd timescale 1043b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; 1044b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(duration); 1045b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0x10000); // rate: 1.0 1046b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0x100); // volume 1047b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0); // reserved 1048b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 1049b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 1050b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeCompositionMatrix(0); // matrix 1051b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 1052b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 1053b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 1054b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 1055b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 1056b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 1057b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTracks.size() + 1); // nextTrackID 1058b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // mvhd 1059b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 1060b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 1061b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) { 1062b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("moov"); 1063b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMvhdBox(durationUs); 106407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (mAreGeoTagsAvailable) { 106507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeUdtaBox(); 106607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 1067e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeMetaBox(); 1068b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t id = 1; 1069b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<Track *>::iterator it = mTracks.begin(); 1070b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mTracks.end(); ++it, ++id) { 1071b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (*it)->writeTrackHeader(mUse32BitOffset); 1072b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 1073b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // moov 1074b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 1075b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 10762cf9c5073ca3342ee52673ad68763fadd2c2be79James Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) { 1077b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("ftyp"); 1078b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 1079b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t fileType; 1080b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (param && param->findInt32(kKeyFileType, &fileType) && 1081b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fileType != OUTPUT_FORMAT_MPEG_4) { 1082b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("3gp4"); 10838284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeInt32(0); 10848284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("isom"); 10858284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("3gp4"); 1086b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 10878284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("mp42"); 10888284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeInt32(0); 1089b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("isom"); 10908284de3be2ac07d8774b15e6565df5aba084db04Robert Shih writeFourcc("mp42"); 1091b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 1092b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 1093b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); 1094b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 1095b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 109607ec01904613a0bac32caaa8444b4690998faed7James Dongstatic bool isTestModeEnabled() { 109707ec01904613a0bac32caaa8444b4690998faed7James Dong#if (PROPERTY_VALUE_MAX < 5) 109807ec01904613a0bac32caaa8444b4690998faed7James Dong#error "PROPERTY_VALUE_MAX must be at least 5" 109907ec01904613a0bac32caaa8444b4690998faed7James Dong#endif 110007ec01904613a0bac32caaa8444b4690998faed7James Dong 110107ec01904613a0bac32caaa8444b4690998faed7James Dong // Test mode is enabled only if rw.media.record.test system 110207ec01904613a0bac32caaa8444b4690998faed7James Dong // property is enabled. 110307ec01904613a0bac32caaa8444b4690998faed7James Dong char value[PROPERTY_VALUE_MAX]; 110407ec01904613a0bac32caaa8444b4690998faed7James Dong if (property_get("rw.media.record.test", value, NULL) && 110507ec01904613a0bac32caaa8444b4690998faed7James Dong (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) { 110607ec01904613a0bac32caaa8444b4690998faed7James Dong return true; 110707ec01904613a0bac32caaa8444b4690998faed7James Dong } 110807ec01904613a0bac32caaa8444b4690998faed7James Dong return false; 110907ec01904613a0bac32caaa8444b4690998faed7James Dong} 111007ec01904613a0bac32caaa8444b4690998faed7James Dong 111170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() { 111207ec01904613a0bac32caaa8444b4690998faed7James Dong // Send session summary only if test mode is enabled 111307ec01904613a0bac32caaa8444b4690998faed7James Dong if (!isTestModeEnabled()) { 111407ec01904613a0bac32caaa8444b4690998faed7James Dong return; 111507ec01904613a0bac32caaa8444b4690998faed7James Dong } 111607ec01904613a0bac32caaa8444b4690998faed7James Dong 111770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 111870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it != mChunkInfos.end(); ++it) { 111970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int trackNum = it->mTrack->getTrackId() << 28; 112070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 112170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, 112270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs); 112370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 112470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong} 112570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 112613aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 112713aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 112813aec890216948b0c364f8f92792129d0335f506James Dong return OK; 112913aec890216948b0c364f8f92792129d0335f506James Dong} 113013aec890216948b0c364f8f92792129d0335f506James Dong 113113aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 113213aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 113313aec890216948b0c364f8f92792129d0335f506James Dong} 113413aec890216948b0c364f8f92792129d0335f506James Dong 113513aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 113613aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 113713aec890216948b0c364f8f92792129d0335f506James Dong} 113820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1139c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 1140c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 114120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1142c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 1143c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 1144c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong buffer->range_length()); 114520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 114620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 114720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 114820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 114920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 115020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 115103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 115203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 115303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 115403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 115503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 115603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 115703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 115803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 115903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 116003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 116103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 116203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 116303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 116403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1165c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 1166c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 116730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 116830ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 116903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1170b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mUse4ByteNalLength) { 1171b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 24; 1172c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1173b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 16) & 0xff; 1174c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1175b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 8) & 0xff; 1176c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1177b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 1178c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1179c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong 1180c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 1181c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 1182c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong length); 1183b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 1184b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 4; 1185b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 118643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LT(length, 65536); 118730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1188b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 8; 1189c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1190b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 1191c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 1192c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 1193b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 2; 1194b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 119530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 119630ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 119730ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 119830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 11997837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 1200674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong const void *ptr, size_t size, size_t nmemb) { 12017837c17063a4c50bc856ba59418516fdab731de7James Dong 12027837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 12037837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 12047b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 1205c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 12061acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 12077b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // The reserved moov box at the beginning of the file 12087b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // is not big enough. Moov box should be written to 12097b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // the end of the file from now on, but not to the 12107b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // in-memory cache. 12117b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 12127b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // We write partial moov box that is in the memory to 12137b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // the file first. 1214c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mBoxes.begin(); 12157837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 12167837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 12177837c17063a4c50bc856ba59418516fdab731de7James Dong } 1218674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong lseek64(mFd, mOffset, SEEK_SET); 1219674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 12207b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong ::write(mFd, ptr, bytes); 12217837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 12227b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong 12237b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // All subsequent moov box content will be written 12247b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong // to the end of the file. 12257837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 12267837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 12277837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 12287837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 12297837c17063a4c50bc856ba59418516fdab731de7James Dong } 12307837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 1231674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 12327837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 12337837c17063a4c50bc856ba59418516fdab731de7James Dong } 12347837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 12357837c17063a4c50bc856ba59418516fdab731de7James Dong} 12367837c17063a4c50bc856ba59418516fdab731de7James Dong 1237e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhangvoid MPEG4Writer::beginBox(uint32_t id) { 1238e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang mBoxes.push_back(mWriteMoovBoxToMemory? 1239e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang mMoovBoxBufferOffset: mOffset); 1240e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 1241e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); 1242e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(id); 1243e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang} 1244e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 124520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 12460c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 124720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 12487837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 12497837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 125020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 125120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 125220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 125320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 125420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 125520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 12560c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 125720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1258c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = *--mBoxes.end(); 125920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 126020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 12617837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 12627837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 12637837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 12647837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 1265c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, offset, SEEK_SET); 12667837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 12677837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 1268c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 12697837c17063a4c50bc856ba59418516fdab731de7James Dong } 127020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 127120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 127220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 1273674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 1); 127420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 127520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 127620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 127720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 1278674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 2); 127920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 128020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 128120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 128220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 1283674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 4); 128420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 128520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 128620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 128720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 1288674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 8); 128920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 129020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 129120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 129220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 1293674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, n + 1); 129420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 129520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 129620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 12970c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 1298674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, 4); 129920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 130020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 130107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 130207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format 130307b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) { 130407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 130507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 130607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 130707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 130807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[9]; 130907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 131007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 131107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%c%.2d.", sign, wholePart); 131207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 131307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%+.2d.", wholePart); 131407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 131507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 131607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 131707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 131807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 131907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 132007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 132107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[4], 5, "%.4d", fractionalPart); 132207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 132307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 132407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 8); 132507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 132607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 132707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format 132807b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) { 132907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 133007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 133107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 133207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 133307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[10]; 133407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 133507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 133607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%c%.3d.", sign, wholePart); 133707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 133807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%+.3d.", wholePart); 133907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 134007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 134107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 134207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 134307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 134407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 134507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 134607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[5], 5, "%.4d", fractionalPart); 134707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 134807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 134907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 9); 135007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 135107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 135207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 135307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 135407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and 135507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000. 135607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and 135707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180] 135807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 135907b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { 136007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Is latitude or longitude out of range? 136107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (latitudex10000 < -900000 || latitudex10000 > 900000 || 136207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong longitudex10000 < -1800000 || longitudex10000 > 1800000) { 136307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return BAD_VALUE; 136407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 136507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 136607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000 = latitudex10000; 136707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000 = longitudex10000; 136807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mAreGeoTagsAvailable = true; 13697c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMoovExtraSize += 30; 137007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return OK; 137107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 137207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 1373e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhangstatus_t MPEG4Writer::setCaptureRate(float captureFps) { 1374e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang if (captureFps <= 0.0f) { 1375e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang return BAD_VALUE; 1376e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 1377e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 13787c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps); 13797c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32; 13807c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang 1381e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang return OK; 1382e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang} 1383e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 138420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 1385674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(data, 1, size); 138620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 138720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 138878a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const { 138978a1a286f736888ae7af8860b2c424af0d978848James Dong return mStreamableFile; 139078a1a286f736888ae7af8860b2c424af0d978848James Dong} 139178a1a286f736888ae7af8860b2c424af0d978848James Dong 1392d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 1393d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1394d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 1395d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1396d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1397d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1398956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 1399d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1400d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1401d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1402d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 14031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 140477e8ae9967a078770416619e99ddb5b010def312James Dong if (!mStreamableFile) { 140577e8ae9967a078770416619e99ddb5b010def312James Dong // Add 1024 bytes as error tolerance 140677e8ae9967a078770416619e99ddb5b010def312James Dong return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes; 140777e8ae9967a078770416619e99ddb5b010def312James Dong } 1408acd234bba9f048971d66890009eeff9a8db94be3James Dong // Be conservative in the estimate: do not exceed 95% of 1409acd234bba9f048971d66890009eeff9a8db94be3James Dong // the target file limit. For small target file size limit, though, 1410acd234bba9f048971d66890009eeff9a8db94be3James Dong // this will not help. 1411acd234bba9f048971d66890009eeff9a8db94be3James Dong return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 1412d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1413d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1414d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 1415d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1416d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 1417d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1418d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1419d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1420d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1421d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1422d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 1423d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 1424d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1425d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1426d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1427d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1428d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 142925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 143025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 143125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 143225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 143325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 143425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 143525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 143625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 143725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 143825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 143925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 144025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 144125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 1442f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 1443a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("setStartTimestampUs: %" PRId64, timeUs); 144443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GE(timeUs, 0ll); 14453c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 1446065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 1447f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 1448a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs); 14493c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 14503c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 14513c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 1452f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 14533c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 14543c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 14553c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 14563c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 145758ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 145858ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 145958ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 146058ae9c530247668f8af36e30d228c716c226b3d4James Dong} 146158ae9c530247668f8af36e30d228c716c226b3d4James Dong 146220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 146320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 146420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 1465b2487f03f12dcafdb801fc0007c8df8412397f44Marco Nelissen MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId) 146620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 146725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 146820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 146920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 1470a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 1471a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 1472eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted(false), 1473bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mTrackId(trackId), 1474c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 1475956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 1476be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 1477c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1478c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1479c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)), 1480c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)), 1481c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1482c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 1483c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 148420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 148525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 1486548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 148713f6284305e4b27395a23db7882d670bdb1bcae1James Dong mReachedEOS(false), 148813f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation(0) { 148919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 14908f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 14911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 14921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 14931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 14949aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC); 14951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 14961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 14971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 14981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1499c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 1500c059860c73678a202bfa33062723e8f82fb779d9James Dong} 1501c059860c73678a202bfa33062723e8f82fb779d9James Dong 15021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() { 15031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1504c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t stcoBoxCount = (mOwner->use32BitFileOffset() 1505c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ? mStcoTableEntries->count() 1506c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong : mCo64TableEntries->count()); 1507c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong int64_t stcoBoxSizeBytes = stcoBoxCount * 4; 1508c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4); 15091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 151078a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 151178a1a286f736888ae7af8860b2c424af0d978848James Dong if (!mOwner->isFileStreamable()) { 151278a1a286f736888ae7af8860b2c424af0d978848James Dong // Reserved free space is not large enough to hold 151378a1a286f736888ae7af8860b2c424af0d978848James Dong // all meta data and thus wasted. 1514c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 + // stsc box size 1515c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries->count() * 4 + // stss box size 1516c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->count() * 8 + // stts box size 1517c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->count() * 8 + // ctts box size 151878a1a286f736888ae7af8860b2c424af0d978848James Dong stcoBoxSizeBytes + // stco box size 151978a1a286f736888ae7af8860b2c424af0d978848James Dong stszBoxSizeBytes; // stsz box size 152078a1a286f736888ae7af8860b2c424af0d978848James Dong } 15211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 15221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 15231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry( 15241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t chunkId, size_t sampleId) { 15251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1526c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->add(htonl(chunkId)); 1527c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->add(htonl(sampleId)); 1528c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->add(htonl(1)); 15291f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 15301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 15311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 1532c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries->add(htonl(sampleId)); 15331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 15341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 15351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry( 153679761ab096f57c3027fad9556c2bc436672d614eJames Dong size_t sampleCount, int32_t duration) { 15371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 15385a217fba010e801c255503602bda4b86ac5a6ac9James Dong if (duration == 0) { 1539377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGW("0-duration samples found: %zu", sampleCount); 15405a217fba010e801c255503602bda4b86ac5a6ac9James Dong } 1541c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->add(htonl(sampleCount)); 1542c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->add(htonl(duration)); 15431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 15441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1545965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::addOneCttsTableEntry( 1546965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong size_t sampleCount, int32_t duration) { 1547965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 1548965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong if (mIsAudio) { 1549965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong return; 1550965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 1551c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->add(htonl(sampleCount)); 1552c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->add(htonl(duration)); 1553965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong} 1554965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 1555c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) { 1556c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mOwner->use32BitFileOffset()) { 1557c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t value = offset; 1558c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries->add(htonl(value)); 1559c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } else { 1560c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries->add(hton64(offset)); 1561c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } 15621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 15631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1564c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 15653856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("setTimeScale"); 1566c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 1567c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 1568c059860c73678a202bfa33062723e8f82fb779d9James Dong 1569c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 1570c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 1571c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 1572c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1573c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 1574c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 1575c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1576c059860c73678a202bfa33062723e8f82fb779d9James Dong 1577c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 1578c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 1579c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1580c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 1581c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1582c059860c73678a202bfa33062723e8f82fb779d9James Dong 158343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mTimeScale, 0); 158419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 158519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 158619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 158719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 158819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 158919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 15909aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim uint32_t type; 15919aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const void *data = NULL; 15929aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim size_t size = 0; 159319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 15949aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mMeta->findData(kKeyAVCC, &type, &data, &size); 15959aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) { 15969aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mMeta->findData(kKeyHVCC, &type, &data, &size); 159719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 159819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 159919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 160019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 16019aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (esds.getCodecSpecificInfo(&data, &size) != OK) { 16029aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim data = NULL; 16039aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim size = 0; 160419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 160519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 160619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 16079aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) { 16089aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mGotAllCodecSpecificData = true; 16099aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 161020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 161120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 161220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 161320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 161420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1615c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStszTableEntries; 1616c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStcoTableEntries; 1617c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mCo64TableEntries; 1618c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStscTableEntries; 1619c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mSttsTableEntries; 1620c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mStssTableEntries; 1621c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong delete mCttsTableEntries; 1622c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 1623c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries = NULL; 1624c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries = NULL; 1625c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries = NULL; 1626c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries = NULL; 1627c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries = NULL; 1628c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries = NULL; 1629c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries = NULL; 1630c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 163120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 163220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 163320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 163420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 163520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 163620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 163793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 16383856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("initTrackingProgressStatus"); 163993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 164093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 164193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 164293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 164393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 164493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 1645a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); 164693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 164793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 164893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 164993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 165093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 165193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 16521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 16531c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 16543856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("ThreadWrapper: %p", me); 16551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 16561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 16571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 16581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 16591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16601c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 16613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("bufferChunk: %p", chunk.mTrack); 16621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 16631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 16641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 16661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 16671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 16691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 16701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 16711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 16721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 167543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK(!"Received a chunk for a unknown track"); 16761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 16771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1678fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) { 1679a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("writeChunkToFile: %" PRId64 " from %s track", 16805410afcbb0af5d29d9f710a1c2978c500f9792dcPannag Sanketi chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video"); 1681fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1682fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong int32_t isFirstSample = true; 1683fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!chunk->mSamples.empty()) { 1684fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 1685fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 16869aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHevc()) 1687fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong ? addLengthPrefixedSample_l(*it) 1688fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong : addSample_l(*it); 1689fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1690fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (isFirstSample) { 1691fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mTrack->addChunkOffset(offset); 1692fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong isFirstSample = false; 16931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 16941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 16951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 16961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 1697fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.erase(it); 16981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1699fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.clear(); 17001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 17011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1702fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() { 17033856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("writeAllChunks"); 17041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 170570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong Chunk chunk; 170670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong while (findChunkToWrite(&chunk)) { 1707e9f6d0579603372fd2547e6c5ba6e114c6f8cba7James Dong writeChunkToFile(&chunk); 170870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong ++outstandingChunks; 17091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 171070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 171170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong sendSessionSummary(); 171270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 17131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 1714377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGD("%zu chunks are written in the last batch", outstandingChunks); 17151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 17161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1717fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 17183856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("findChunkToWrite"); 17191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 17211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 17221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 17231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 17241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 17251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 17261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 17271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 17281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 17291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 17301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 17311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 17321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 17343856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Nothing to be written after all"); 1735fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 17361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 17371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 17391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 17401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1741fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 17421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 17431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 17441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 1745fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong *chunk = *(it->mChunks.begin()); 1746fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong it->mChunks.erase(it->mChunks.begin()); 1747fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong CHECK_EQ(chunk->mTrack, track); 174870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 174970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t interChunkTimeUs = 175070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 175170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 175270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs = interChunkTimeUs; 175370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 175470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 1755fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return true; 17561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 17571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1758fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1759fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 17601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 17611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17621c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 17633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("threadFunc"); 17641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1765a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 1766fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1767fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Mutex::Autolock autoLock(mLock); 17681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 1769fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Chunk chunk; 1770fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong bool chunkFound = false; 1771fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1772fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 17731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 17741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 17751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1776de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // In real time recording mode, write without holding the lock in order 1777de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // to reduce the blocking time for media track threads. 1778de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // Otherwise, hold the lock until the existing chunks get written to the 1779de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui // file. 1780fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (chunkFound) { 1781de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mIsRealTimeRecording) { 1782de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mLock.unlock(); 1783de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 1784fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeChunkToFile(&chunk); 1785de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mIsRealTimeRecording) { 1786de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui mLock.lock(); 1787de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 1788fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong } 17891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1790fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1791fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeAllChunks(); 17921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 17931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17941c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 17953856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("startWriterThread"); 17961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 17981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1799e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 18001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 18011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 18021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 18031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 180470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mPrevChunkTimestampUs = 0; 180570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mMaxInterChunkDurUs = 0; 18061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 18071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 18081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 18091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 18101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 18111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 18121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 18131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 1814411ba422e3635d534928ffd81abf54f4f291c739James Dong mWriterThreadStarted = true; 18151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 18161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 18171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 18181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 181993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1820a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1821a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1822a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1823a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1824a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 182525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 182693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 182719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 182819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 182919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 183070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mStartTimeRealUs = startTimeUs; 183119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 183213f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t rotationDegrees; 183313f6284305e4b27395a23db7882d670bdb1bcae1James Dong if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 183413f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation = rotationDegrees; 183513f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 183613f6284305e4b27395a23db7882d670bdb1bcae1James Dong 183793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 183893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1839f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1840de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) { 1841a472613aec322e25891abf5c77bf3f7e3c244920James Dong /* 1842a472613aec322e25891abf5c77bf3f7e3c244920James Dong * This extra delay of accepting incoming audio/video signals 1843a472613aec322e25891abf5c77bf3f7e3c244920James Dong * helps to align a/v start time at the beginning of a recording 1844a472613aec322e25891abf5c77bf3f7e3c244920James Dong * session, and it also helps eliminate the "recording" sound for 1845a472613aec322e25891abf5c77bf3f7e3c244920James Dong * camcorder applications. 1846a472613aec322e25891abf5c77bf3f7e3c244920James Dong * 184786b7f47aa7482424cf8fd248f1315311919be3b0James Dong * If client does not set the start time offset, we fall back to 184886b7f47aa7482424cf8fd248f1315311919be3b0James Dong * use the default initial delay value. 1849a472613aec322e25891abf5c77bf3f7e3c244920James Dong */ 185086b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 185186b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 185286b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 185386b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 185486b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeUs += startTimeOffsetUs; 1855a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 1856a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 1857a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1858f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1859a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1860f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 186125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 186225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 186325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 186425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 186520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 186620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 186720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 186820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 186920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 187020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1871eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted = true; 1872c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 187325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1874956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 18751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes = 0; 187643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = 0; 187720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 187825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 187920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 188025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 188125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 188220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 188320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 188437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1885a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 188637187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1887a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1888a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 188937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 189072cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang ALOGD("%s track stopping", mIsAudio? "Audio": "Video"); 1891eaae38445a340c4857c1c5569475879a728e63b7James Dong if (!mStarted) { 189229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Stop() called but track is not started"); 1893eaae38445a340c4857c1c5569475879a728e63b7James Dong return ERROR_END_OF_STREAM; 1894eaae38445a340c4857c1c5569475879a728e63b7James Dong } 1895eaae38445a340c4857c1c5569475879a728e63b7James Dong 189620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 189737187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 189820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 189920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 190020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 190172cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); 190272cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang mSource->stop(); 190372cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang ALOGD("%s track source stopped", mIsAudio? "Audio": "Video"); 190472cecca17d735db6532c45f0a7e10c47ee6f065aChong Zhang 190520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 190620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 1907377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); 190837187916a486504acaf83bea30147eb5fbf46ae5James Dong 1909b8a805261bf0282e992d3608035e47d05a898710Steve Block ALOGD("%s track stopped", mIsAudio? "Audio": "Video"); 191037187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 191120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 191220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 191325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 191425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 191525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 191625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 191720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 191820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 191920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 192020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 192137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 1922377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT return (void *)(uintptr_t)err; 192320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 192420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 19263856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("getNalUnitType: %d", byte); 19273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 19293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 19303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 19313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 19333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 19343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19353856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("parseParamSet"); 19363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 19373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 19383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 193947d8891199f40a3a89c2910e4407f82a125df43bLajos Molnar const uint8_t *nextStartCode = findNextNalStartCode(data, length); 19403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 19413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 194229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Param set is malformed, since its length is 0"); 19433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 19443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 19473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 19483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 194929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Seq parameter set malformed"); 19503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 19513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 19533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 19543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 19553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 19563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 19573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 19583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 19593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 196007b2fbfb40770f3be0f674596f2e51d257c6d2bdLajos Molnar // COULD DO: set profile/level to the lowest required to support all SPSs 196129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Inconsistent profile/level found in seq parameter sets"); 19623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 19633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 19663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 19673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 19683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 19703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 19713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 19733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 19743856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("copyAVCCodecSpecificData"); 19753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 19773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 19789aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return copyCodecSpecificData(data, size, 4 + 7); 19799aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim} 19809aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 19819aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kimstatus_t MPEG4Writer::Track::copyHEVCCodecSpecificData( 19829aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const uint8_t *data, size_t size) { 19839aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGV("copyHEVCCodecSpecificData"); 19849aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 19859aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2) 19869aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return copyCodecSpecificData(data, size, 23); 19879aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim} 19889aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 19899aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kimstatus_t MPEG4Writer::Track::copyCodecSpecificData( 19909aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const uint8_t *data, size_t size, size_t minLength) { 19919aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (size < minLength) { 1992377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Codec specific data length too short: %zu", size); 19933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 19943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 19953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 19979aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (mCodecSpecificData == NULL) { 19989aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGE("Failed allocating codec specific data"); 19999aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return NO_MEMORY; 20009aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 20019aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mCodecSpecificDataSize = size; 20023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 20033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 20043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 20053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 20073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 20083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20093856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("parseAVCCodecSpecificData"); 20103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 20113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 20123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 20133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 20143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 20153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 20163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 20173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 20183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 20193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 20203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 20213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 20223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 20233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 20243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 202529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("SPS must come before PPS"); 20263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 20293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 20303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 20323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 20333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 203429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("SPS must come before PPS"); 20353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 20383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 20393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 20413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 204229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Only SPS and PPS Nal units are expected"); 20433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 20473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 20513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 20523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 20533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 20543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 20573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 20583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 20593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 206029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Cound not find sequence parameter set"); 20613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 2065377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets); 20663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 20703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 20713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 20723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 20733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 207429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Cound not find picture parameter set"); 20753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 2078377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets); 20793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 20803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20821374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// FIXME: 20831374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above 20841374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// and remove #if 0 20851374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#if 0 20863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 20873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 20883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 20893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 20903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 209129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 20923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 20933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 20951374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#endif 20963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 20973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 2098548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 209903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 210003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 2101548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 210203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 210329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Already have codec specific data"); 210403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 210503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 210603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 21073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 2108377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT ALOGE("Codec specific data length too short: %zu", size); 210903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 211003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 211103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 21123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 21133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 21143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 211503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 211603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 21173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 211803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 211903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 212003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 21213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 21223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 212303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 21249aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (mCodecSpecificData == NULL) { 21259aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mCodecSpecificDataSize = 0; 21269aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGE("Failed allocating codec specific data"); 21279aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return NO_MEMORY; 21289aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 212903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 21303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 21313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 21323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 21333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 213403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 21353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 2136b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 2137b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 3; // length size == 4 bytes 2138b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 2139b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 1; // length size == 2 bytes 2140b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 214103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 21423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 21433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 21443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 21453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 21463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 21473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 21483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 21493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 21503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 21513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 21523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 21533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 21543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 21553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 21563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 21573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 21583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 21593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 21603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 21613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 21623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 21633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 21643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 21653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 21663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 21673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 21683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 21693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 21703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 21713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 21723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 217303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 217403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 217503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 217603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 21779aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 21789aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kimstatus_t MPEG4Writer::Track::parseHEVCCodecSpecificData( 21799aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const uint8_t *data, size_t size, HevcParameterSets ¶mSets) { 21809aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 21819aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGV("parseHEVCCodecSpecificData"); 21829aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const uint8_t *tmp = data; 21839aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const uint8_t *nextStartCode = data; 21849aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim size_t bytesLeft = size; 21859aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 218647d8891199f40a3a89c2910e4407f82a125df43bLajos Molnar nextStartCode = findNextNalStartCode(tmp + 4, bytesLeft - 4); 21879aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4); 21889aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (err != OK) { 21899aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return ERROR_MALFORMED; 21909aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 21919aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 21929aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim // Move on to find the next parameter set 21939aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim bytesLeft -= nextStartCode - tmp; 21949aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim tmp = nextStartCode; 21959aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 21969aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 21979aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim size_t csdSize = 23; 21989aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const size_t numNalUnits = paramSets.getNumNalUnits(); 21999aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) { 22009aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim int type = kMandatoryHevcNalUnitTypes[i]; 22019aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim size_t numParamSets = paramSets.getNumNalUnitsOfType(type); 22029aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (numParamSets == 0) { 22039aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGE("Cound not find NAL unit of type %d", type); 22049aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return ERROR_MALFORMED; 22059aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22069aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22079aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) { 22089aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim int type = kHevcNalUnitTypes[i]; 22099aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim size_t numParamSets = paramSets.getNumNalUnitsOfType(type); 22109aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (numParamSets > 0xffff) { 22119aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGE("Too many seq parameter sets (%zu) found", numParamSets); 22129aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return ERROR_MALFORMED; 22139aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22149aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim csdSize += 3; 22159aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim for (size_t j = 0; j < numNalUnits; ++j) { 22169aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (paramSets.getType(j) != type) { 22179aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim continue; 22189aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22199aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim csdSize += 2 + paramSets.getSize(j); 22209aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22219aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22229aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mCodecSpecificDataSize = csdSize; 22239aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return OK; 22249aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim} 22259aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 22269aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kimstatus_t MPEG4Writer::Track::makeHEVCCodecSpecificData( 22279aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim const uint8_t *data, size_t size) { 22289aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 22299aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (mCodecSpecificData != NULL) { 22309aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGE("Already have codec specific data"); 22319aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return ERROR_MALFORMED; 22329aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22339aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 22349aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (size < 4) { 22359aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGE("Codec specific data length too short: %zu", size); 22369aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return ERROR_MALFORMED; 22379aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22389aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 22399aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim // Data is in the form of HEVCCodecSpecificData 22409aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (memcmp("\x00\x00\x00\x01", data, 4)) { 22419aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return copyHEVCCodecSpecificData(data, size); 22429aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22439aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 22449aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim HevcParameterSets paramSets; 22459aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) { 22463d53e1c0dd7760f3ca58ff75e74cd7fcf4bc08ccWonsik Kim ALOGE("failed parsing codec specific data"); 22479aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return ERROR_MALFORMED; 22489aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22499aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 22509aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mCodecSpecificData = malloc(mCodecSpecificDataSize); 22519aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (mCodecSpecificData == NULL) { 22529aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mCodecSpecificDataSize = 0; 22539aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ALOGE("Failed allocating codec specific data"); 22549aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return NO_MEMORY; 22559aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22569aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData, 22573d53e1c0dd7760f3ca58ff75e74cd7fcf4bc08ccWonsik Kim &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 4 : 2); 22589aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (err != OK) { 22593d53e1c0dd7760f3ca58ff75e74cd7fcf4bc08ccWonsik Kim ALOGE("failed constructing HVCC atom"); 22609aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return err; 22619aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } 22629aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 22639aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim return OK; 22649aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim} 22659aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 2266872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 2267872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that 2268872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information 2269872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio 2270872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger 2271872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 2272872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined. 2273872a481558350634a3fd5cb67939de288af00ecbJames Dong */ 2274872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 2275872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftTimeUs = 0; 2276872a481558350634a3fd5cb67939de288af00ecbJames Dong if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 2277872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 2278872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 2279872a481558350634a3fd5cb67939de288af00ecbJames Dong mOwner->setDriftTimeUs(timeUs); 2280872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2281872a481558350634a3fd5cb67939de288af00ecbJames Dong} 2282872a481558350634a3fd5cb67939de288af00ecbJames Dong 228337187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 228430ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 228513aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 228643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong const bool hasMultipleTracks = (mOwner->numTracks() > 1); 228713aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 228813aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 22897c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar int32_t nActualFrames = 0; // frames containing non-CSD data (non-0 length) 229013aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 2291965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t lastTimestampUs = 0; // Previous sample time stamp 2292965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t lastDurationUs = 0; // Between the previous two samples 2293965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t currDurationTicks = 0; // Timescale based ticks 2294965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t lastDurationTicks = 0; // Timescale based ticks 2295965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 2296000e18370baae60ffd9f25b509501dd8c26deabfJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 2297a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 2298965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t timestampUs = 0; 2299000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t cttsOffsetTimeUs = 0; 2300000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks 2301000e18370baae60ffd9f25b509501dd8c26deabfJames Dong int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks 230243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry 2303c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t lastSamplesPerChunk = 0; 2304e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2305a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong if (mIsAudio) { 2306a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 2307a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } else { 2308a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 2309a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } 2310de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui 2311de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mOwner->isRealTimeRecording()) { 2312de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); 2313de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui } 2314985f838934510983d8a887461e98dca60a6e858fJames Dong 2315d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 231620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 231793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 231820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 231911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih const char *trackName = mIsAudio ? "Audio" : "Video"; 232093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 232120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 232220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 232320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 232413aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 232520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 232620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 232720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2328a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 2329a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 2330a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 2331a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 2332a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 2333a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 2334a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 2335a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2336a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 233730ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 233830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 233903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 234003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 234103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 23427c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar // if config format (at track addition) already had CSD, keep that 23437c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar // UNLESS we have not received any frames yet. 23447c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar // TODO: for now the entire CSD has to come in one frame for encoders, even though 23457c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar // they need to be spread out for decoders. 23467c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar if (mGotAllCodecSpecificData && nActualFrames > 0) { 23477c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar ALOGI("ignoring additional CSD for video track after first frame"); 23487c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar } else { 23497c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar mMeta = mSource->getFormat(); // get output format after format change 23507c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar 23517c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar if (mIsAvc) { 23527c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar status_t err = makeAVCCodecSpecificData( 23537c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar (const uint8_t *)buffer->data() 23547c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar + buffer->range_offset(), 23557c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar buffer->range_length()); 23567c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar CHECK_EQ((status_t)OK, err); 23577c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar } else if (mIsHevc) { 23587c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar status_t err = makeHEVCCodecSpecificData( 23597c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar (const uint8_t *)buffer->data() 23607c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar + buffer->range_offset(), 23617c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar buffer->range_length()); 23627c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar CHECK_EQ((status_t)OK, err); 23637c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar } else if (mIsMPEG4) { 23647c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), 23657c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar buffer->range_length()); 23667c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar } 236730ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 236830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 236930ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 237030ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 237130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 2372548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 237330ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 2374a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2375a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 23767c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar ++nActualFrames; 23777c9ea89cbe3e42e0d94b1790ae1d424a9c16ce08Lajos Molnar 2378d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 2379d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 2380d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 2381d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 2382d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 2383d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 2384d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 2385d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 2386d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 2387d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 23889aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (mIsAvc || mIsHevc) StripStartcode(copy); 2389e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 2390b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong size_t sampleSize = copy->range_length(); 23919aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim if (mIsAvc || mIsHevc) { 2392b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 2393b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 4; 2394b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 2395b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 2; 2396b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 2397b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 2398050b28a593350047845a45a14cc5026221ac1620James Dong 2399d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 24001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes += sampleSize; 24011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong updateTrackSizeEstimate(); 24021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 2403d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 2404316d08c1f115499fb0ccd82d22592bed7e54aad7Hangyu Kuang ALOGW("Recorded file size exceeds limit %" PRId64 "bytes", 2405316d08c1f115499fb0ccd82d22592bed7e54aad7Hangyu Kuang mOwner->mMaxFileSizeLimitBytes); 2406d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2407d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2408d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2409d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 2410316d08c1f115499fb0ccd82d22592bed7e54aad7Hangyu Kuang ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds", 2411316d08c1f115499fb0ccd82d22592bed7e54aad7Hangyu Kuang mOwner->mMaxFileDurationLimitUs); 2412d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2413d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2414d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2415d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2416050b28a593350047845a45a14cc5026221ac1620James Dong 2417d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 2418d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2419d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 2420d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 2421d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 2422c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { 242370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mFirstSampleTimeRealUs = systemTime() / 1000; 2424f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 2425f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 24268428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs = mStartTimestampUs; 24273c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 242848c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 2429a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 24308428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 243111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { 243211f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 243311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 243411f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 243511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 24368428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 243711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { 243811f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 243911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 244011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 244111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 24428428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs += pausedDurationUs - lastDurationUs; 2443a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 2444a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2445a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2446a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 244711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 244811f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 244911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 245011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 245111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2452000e18370baae60ffd9f25b509501dd8c26deabfJames Dong if (!mIsAudio) { 2453965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong /* 2454965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong * Composition time: timestampUs 2455965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong * Decoding time: decodingTimeUs 2456000e18370baae60ffd9f25b509501dd8c26deabfJames Dong * Composition time offset = composition time - decoding time 2457965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong */ 2458965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong int64_t decodingTimeUs; 2459965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs)); 2460965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong decodingTimeUs -= previousPausedDurationUs; 2461000e18370baae60ffd9f25b509501dd8c26deabfJames Dong cttsOffsetTimeUs = 2462000e18370baae60ffd9f25b509501dd8c26deabfJames Dong timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; 246311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { 246411f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 246511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 246611f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 246711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2468965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong timestampUs = decodingTimeUs; 2469a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, 2470000e18370baae60ffd9f25b509501dd8c26deabfJames Dong timestampUs, cttsOffsetTimeUs); 2471000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 2472000e18370baae60ffd9f25b509501dd8c26deabfJames Dong // Update ctts box table if necessary 2473000e18370baae60ffd9f25b509501dd8c26deabfJames Dong currCttsOffsetTimeTicks = 2474000e18370baae60ffd9f25b509501dd8c26deabfJames Dong (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; 247511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { 247611f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 247711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 247811f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 247911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2480c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { 248143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // Force the first ctts table entry to have one single entry 248243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // so that we can do adjustment for the initial track start 248343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // time offset easily in writeCttsBox(). 248443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 248543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong addOneCttsTableEntry(1, currCttsOffsetTimeTicks); 248643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong cttsSampleCount = 0; // No sample in ctts box is pending 248743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } else { 248843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) { 248943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 249043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 249143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong cttsSampleCount = 1; // One sample in ctts box is pending 249243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } else { 249343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong ++cttsSampleCount; 249443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 249543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 2496000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 2497000e18370baae60ffd9f25b509501dd8c26deabfJames Dong // Update ctts time offset range 2498c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { 2499000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2500000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2501000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } else { 2502000e18370baae60ffd9f25b509501dd8c26deabfJames Dong if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) { 2503000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2504000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) { 2505000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2506000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } 2507000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } 2508000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 2509965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 2510872a481558350634a3fd5cb67939de288af00ecbJames Dong 2511de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui if (mOwner->isRealTimeRecording()) { 2512872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2513872a481558350634a3fd5cb67939de288af00ecbJames Dong updateDriftTime(meta_data); 2514e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2515e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2516872a481558350634a3fd5cb67939de288af00ecbJames Dong 251711f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 251811f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 251911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih return ERROR_MALFORMED; 252011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih } 252111f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih 2522a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, 252311f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih trackName, timestampUs, previousPausedDurationUs); 2524c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 2525c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 25263b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 25273b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 25285a217fba010e801c255503602bda4b86ac5a6ac9James Dong // We need to use the time scale based ticks, rather than the 25295a217fba010e801c255503602bda4b86ac5a6ac9James Dong // timestamp itself to determine whether we have to use a new 25305a217fba010e801c255503602bda4b86ac5a6ac9James Dong // stts entry, since we may have rounding errors. 25315a217fba010e801c255503602bda4b86ac5a6ac9James Dong // The calculation is intended to reduce the accumulated 25325a217fba010e801c255503602bda4b86ac5a6ac9James Dong // rounding errors. 25335a217fba010e801c255503602bda4b86ac5a6ac9James Dong currDurationTicks = 25345a217fba010e801c255503602bda4b86ac5a6ac9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 25355a217fba010e801c255503602bda4b86ac5a6ac9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2536c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (currDurationTicks < 0ll) { 2537f85a83af8c6a98b46c394c32b90b09214a68f3e4Hangyu Kuang ALOGE("do not support out of order frames (timestamp: %lld < last: %lld for %s track", 2538f85a83af8c6a98b46c394c32b90b09214a68f3e4Hangyu Kuang (long long)timestampUs, (long long)lastTimestampUs, trackName); 253911f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih copy->release(); 25400332fadec6e91c37fe39ab92b2c02922370bc853Hangyu Kuang mSource->stop(); 2541c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong return UNKNOWN_ERROR; 25428c460498c028888c533ab442be12b6d4b669b965James Dong } 25438c460498c028888c533ab442be12b6d4b669b965James Dong 254485fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // if the duration is different for this sample, see if it is close enough to the previous 254585fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // duration that we can fudge it and use the same value, to avoid filling the stts table 254685fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // with lots of near-identical entries. 254785fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // "close enough" here means that the current duration needs to be adjusted by less 254885fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // than 0.1 milliseconds 254985fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { 255085fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL 255185fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen + (mTimeScale / 2)) / mTimeScale; 255285fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen if (deltaUs > -100 && deltaUs < 100) { 255385fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // use previous ticks, and adjust timestamp as if it was actually that number 255485fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen // of ticks 255585fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen currDurationTicks = lastDurationTicks; 255685fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen timestampUs += deltaUs; 255785fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen } 255885fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen } 255985fcbd6aec4eab3368e9266be0a1151a081f204dMarco Nelissen 2560c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries->add(htonl(sampleSize)); 2561c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() > 2) { 2562c059860c73678a202bfa33062723e8f82fb779d9James Dong 2563a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Force the first sample to have its own stts entry so that 2564a472613aec322e25891abf5c77bf3f7e3c244920James Dong // we can adjust its value later to maintain the A/V sync. 2565c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) { 256679761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount, lastDurationTicks); 2567be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 2568be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2569be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 2570be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2571965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 2572be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2573be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 2574c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) { 2575be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 2576be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 25778644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 2578be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2579a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, 258011f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih trackName, timestampUs, lastTimestampUs); 25818644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 2582c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 25838644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 258420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2585d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 2586c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong addOneStssTableEntry(mStszTableEntries->count()); 2587d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 2588d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 258993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 259093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 259193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 259293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 2593faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 259493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 259543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 25969aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addLengthPrefixedSample_l(copy) 259758ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 2598c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 2599c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t count = (mOwner->use32BitFileOffset() 2600c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong ? mStcoTableEntries->count() 2601c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong : mCo64TableEntries->count()); 2602c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 2603c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (count == 0) { 26041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addChunkOffset(offset); 260558ae9c530247668f8af36e30d228c716c226b3d4James Dong } 260658ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 260758ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 260858ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 260958ae9c530247668f8af36e30d228c716c226b3d4James Dong } 261013aec890216948b0c364f8f92792129d0335f506James Dong 261113aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 261213aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 26131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, 1); 26141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 261513aec890216948b0c364f8f92792129d0335f506James Dong } else { 261613aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 261713aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 261813aec890216948b0c364f8f92792129d0335f506James Dong } else { 261943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 262043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > interleaveDurationUs) { 262143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > mMaxChunkDurationUs) { 262243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = chunkDurationUs; 262343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 262413aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 262513aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 2626c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong lastSamplesPerChunk != mChunkSamples.size()) { 2627c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong lastSamplesPerChunk = mChunkSamples.size(); 2628c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong addOneStscTableEntry(nChunks, lastSamplesPerChunk); 262913aec890216948b0c364f8f92792129d0335f506James Dong } 26301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 263113aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 263213aec890216948b0c364f8f92792129d0335f506James Dong } 263313aec890216948b0c364f8f92792129d0335f506James Dong } 263413aec890216948b0c364f8f92792129d0335f506James Dong } 263513aec890216948b0c364f8f92792129d0335f506James Dong 263620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 263725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 263845c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong if (isTrackMalFormed()) { 2639690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 2640f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 264145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 2642bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, -1, err); 2643be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 264413aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 264543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 2646c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong addOneStscTableEntry(1, mStszTableEntries->count()); 264758ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 26481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, mChunkSamples.size()); 26491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 265013aec890216948b0c364f8f92792129d0335f506James Dong } 265113aec890216948b0c364f8f92792129d0335f506James Dong 2652be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 2653be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 2654be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 2655c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 1) { 26568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 265779761ab096f57c3027fad9556c2bc436672d614eJames Dong lastDurationTicks = 0; 2658be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2659be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 2660be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2661a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2662c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() <= 2) { 266379761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(1, lastDurationTicks); 2664a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (sampleCount - 1 > 0) { 266579761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); 2666a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2667a472613aec322e25891abf5c77bf3f7e3c244920James Dong } else { 266879761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount, lastDurationTicks); 2669a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2670a472613aec322e25891abf5c77bf3f7e3c244920James Dong 267143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // The last ctts box may not have been written yet, and this 267243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong // is to make sure that we write out the last ctts box. 267343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) { 267443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong if (cttsSampleCount > 0) { 267543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 267643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 267743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong } 267843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong 2679c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 268025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 268143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 268243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong sendTrackSummary(hasMultipleTracks); 268343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 2684df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 268511f15ddbca475b5f6a3d7970b22234e04c595b37Robert Shih count, nZeroLengthFrames, mStszTableEntries->count(), trackName); 2686872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2687a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); 2688872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2689365a963142093a1cd8efdcea76b5f65096a5b115James Dong 269037187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 269137187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 269237187916a486504acaf83bea30147eb5fbf46ae5James Dong } 269337187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 2694365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 2695365a963142093a1cd8efdcea76b5f65096a5b115James Dong 269645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dongbool MPEG4Writer::Track::isTrackMalFormed() const { 2697c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mStszTableEntries->count() == 0) { // no samples written 269829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("The number of recorded samples is 0"); 269945c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return true; 270045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong } 270145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 2702c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (!mIsAudio && mStssTableEntries->count() == 0) { // no sync frames for video 270329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("There are no sync frames for video track"); 270445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return true; 270545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong } 270645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 270745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong if (OK != checkCodecSpecificData()) { // no codec specific data 270845c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return true; 270945c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong } 271045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 271145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong return false; 271245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong} 271345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong 271443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 271507ec01904613a0bac32caaa8444b4690998faed7James Dong 271607ec01904613a0bac32caaa8444b4690998faed7James Dong // Send track summary only if test mode is enabled. 271707ec01904613a0bac32caaa8444b4690998faed7James Dong if (!isTestModeEnabled()) { 271807ec01904613a0bac32caaa8444b4690998faed7James Dong return; 271907ec01904613a0bac32caaa8444b4690998faed7James Dong } 272007ec01904613a0bac32caaa8444b4690998faed7James Dong 272143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int trackNum = (mTrackId << 28); 272243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 272343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 272443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 272543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mIsAudio? 0: 1); 272643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 272743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 272843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 272943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mTrackDurationUs / 1000); 273043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 273143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 273243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 2733c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries->count()); 273443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 273586b7f47aa7482424cf8fd248f1315311919be3b0James Dong { 273686b7f47aa7482424cf8fd248f1315311919be3b0James Dong // The system delay time excluding the requested initial delay that 273786b7f47aa7482424cf8fd248f1315311919be3b0James Dong // is used to eliminate the recording sound. 273886b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 273986b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 274086b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 274186b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 274286b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t initialDelayUs = 274386b7f47aa7482424cf8fd248f1315311919be3b0James Dong mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 274486b7f47aa7482424cf8fd248f1315311919be3b0James Dong 274586b7f47aa7482424cf8fd248f1315311919be3b0James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 274670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 274770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong (initialDelayUs) / 1000); 274886b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 274970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 275007ec01904613a0bac32caaa8444b4690998faed7James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 275107ec01904613a0bac32caaa8444b4690998faed7James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, 275207ec01904613a0bac32caaa8444b4690998faed7James Dong mMdatSizeBytes / 1024); 275307ec01904613a0bac32caaa8444b4690998faed7James Dong 275443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (hasMultipleTracks) { 275543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 275643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 275743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs / 1000); 275870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 275970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 276070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (mStartTimestampUs != moovStartTimeUs) { 276170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 276270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 276370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 276470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong startTimeOffsetUs / 1000); 276570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 276643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 276743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong} 276843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 2769faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2770a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); 2771c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong 2772215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 2773215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 2774a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); 2775bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 277693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 277793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 277893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 277993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 2780faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 2781bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong size_t trackId, int64_t timeUs, status_t err) { 2782faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 2783bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t trackNum = (trackId << 28); 2784faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2785faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 2786faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 2787faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 2788bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2789bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 2790faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2791faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2792faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2793faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2794faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 2795faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 2796bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2797bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 2798faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2799faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 2800faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 2801bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2802bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 2803faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 2804faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2805faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 2806faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2807d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2808a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); 2809e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2810d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 2811e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2812e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2813e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 2814a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); 2815e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2816e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 2817e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2818e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2819de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghuibool MPEG4Writer::isRealTimeRecording() const { 2820de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui return mIsRealTimeRecording; 2821de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui} 2822de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui 2823b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() { 2824b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong return mUse4ByteNalLength; 2825b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong} 2826b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 28271c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 28283856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("bufferChunk"); 28291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 28301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 28311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 283213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 283320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 283420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 28353b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 2836c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 283720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 283820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2839d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2840d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 2841d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 2842d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2843690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 2844690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 2845690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2846690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2847690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 28489aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) || 28499aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { 2850690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 2851690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 285229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Missing codec specific data"); 2853690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2854690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2855690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 2856690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 2857690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 285829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Unexepected codec specific data found"); 2859690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2860690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2861690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2862690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 2863690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 2864690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2865b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 286620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 28673856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("%s track time scale: %d", 28681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 28698f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 2870efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson uint32_t now = getMpeg4Time(); 2871b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("trak"); 2872b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeTkhdBox(now); 2873b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdia"); 2874b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMdhdBox(now); 2875b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeHdlrBox(); 2876b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("minf"); 2877b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2878b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSmhdBox(); 2879b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2880b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVmhdBox(); 2881b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2882b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDinfBox(); 2883b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStblBox(use32BitOffset); 2884b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // minf 2885b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mdia 2886b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // trak 2887b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2888b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2889b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 2890b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stbl"); 2891b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsd"); 2892b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2893b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count 2894b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2895b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAudioFourCCBox(); 2896b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2897b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVideoFourCCBox(); 2898b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2899b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsd 2900b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSttsBox(); 2901965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong writeCttsBox(); 2902b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!mIsAudio) { 2903b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStssBox(); 2904b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2905b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStszBox(); 2906b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStscBox(); 2907b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStcoBox(use32BitOffset); 2908b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stbl 2909b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2910b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2911b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() { 2912b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2913b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2914b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 29158b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan const char *fourcc = getFourCCForMime(mime); 29168b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan if (fourcc == NULL) { 291729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Unknown mime type '%s'.", mime); 2918b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2919b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2920b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 29218b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan mOwner->beginBox(fourcc); // video format 2922b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2923b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2924b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // data ref index 2925b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2926b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2927b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2928b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2929b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2930b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2931b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 2932b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeyWidth, &width); 2933b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 2934b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2935b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2936b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(width); 2937b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(height); 2938b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // horiz resolution 2939b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // vert resolution 2940b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2941b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // frame count 2942c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo mOwner->writeInt8(0); // compressor string length 2943c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo mOwner->write(" ", 31); 2944b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x18); // depth 2945b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(-1); // predefined 2946b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 294743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LT(23 + mCodecSpecificDataSize, 128); 2948b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2949b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2950b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4vEsdsBox(); 2951b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2952b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeD263Box(); 2953b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2954b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAvccBox(); 29559aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { 29569aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim writeHvccBox(); 2957b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2958b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2959b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writePaspBox(); 296058fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar writeColrBox(); 2961b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mp4v, s263 or avc1 2962b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2963b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 296458fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnarvoid MPEG4Writer::Track::writeColrBox() { 296558fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar ColorAspects aspects; 296658fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar memset(&aspects, 0, sizeof(aspects)); 296758fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar // TRICKY: using | instead of || because we want to execute all findInt32-s 296858fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar if (mMeta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries) 296958fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar | mMeta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer) 297058fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar | mMeta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs) 297158fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar | mMeta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) { 297258fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar int32_t primaries, transfer, coeffs; 297358fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar bool fullRange; 297458fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar ColorUtils::convertCodecColorAspectsToIsoAspects( 297558fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar aspects, &primaries, &transfer, &coeffs, &fullRange); 297658fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar mOwner->beginBox("colr"); 297758fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar mOwner->writeFourcc("nclx"); 297858fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar mOwner->writeInt16(primaries); 297958fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar mOwner->writeInt16(transfer); 298058fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar mOwner->writeInt16(coeffs); 298158fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar mOwner->writeInt8(fullRange ? 128 : 0); 298258fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar mOwner->endBox(); // colr 298358fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar } 298458fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar} 298558fb7c6e1a9244dd7215a647388c440d8d75851bLajos Molnar 2986b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() { 2987b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2988b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2989b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 29908b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan const char *fourcc = getFourCCForMime(mime); 29918b07404cfe564885045a63bb592d6b6dc838b408Praveen Chavan if (fourcc == NULL) { 299229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Unknown mime type '%s'.", mime); 2993b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2994b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2995b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2996b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(fourcc); // audio format 2997b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2998b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2999b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x1); // data ref index 3000b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 3001b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 3002b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t nChannels; 3003b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 3004b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(nChannels); // channel count 3005b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(16); // sample size 3006b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 3007b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 3008b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3009b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t samplerate; 3010b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeySampleRate, &samplerate); 3011b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 3012b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(samplerate << 16); 3013b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 3014b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4aEsdsBox(); 3015b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 3016b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 3017b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDamrBox(); 3018b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 3019b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 3020b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3021b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3022b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() { 3023b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 3024b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 302543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mCodecSpecificDataSize, 0); 3026b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3027b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Make sure all sizes encode to a single byte. 302843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_LT(mCodecSpecificDataSize + 23, 128); 3029b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3030b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3031b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 3032b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 3033b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000);// ES_ID 3034b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x00); 3035b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3036b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 3037b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 3038b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 3039b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x15); // streamType AudioStream 3040b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3041b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x03); // XXX 304246f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar mOwner->writeInt8(0x00); // buffer size 24-bit (0x300) 304346f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar 304496bdf620189622005e83b4f1421c4f25b7fa1729Lajos Molnar int32_t avgBitrate = 0; 304546f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar (void)mMeta->findInt32(kKeyBitRate, &avgBitrate); 304696bdf620189622005e83b4f1421c4f25b7fa1729Lajos Molnar int32_t maxBitrate = 0; 304746f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate); 304846f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar mOwner->writeInt32(maxBitrate); 304946f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar mOwner->writeInt32(avgBitrate); 3050b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3051b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 3052b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 3053b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3054b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3055b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 3056b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 3057b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 3058b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 3059b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 3060b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 3061b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3062b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 3063b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3064b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3065b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() { 3066b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 306743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mCodecSpecificDataSize, 0); 3068b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 3069b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3070b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3071b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3072b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 3073b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 3074b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000); // ES_ID 3075b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x1f); 3076b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3077b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 3078b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 3079b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 3080b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x11); // streamType VisualStream 3081b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3082b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData[] = { 308346f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar 0x01, 0x77, 0x00, // buffer size 96000 bytes 3084b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 3085b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData, sizeof(kData)); 3086b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 308796bdf620189622005e83b4f1421c4f25b7fa1729Lajos Molnar int32_t avgBitrate = 0; 308846f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar (void)mMeta->findInt32(kKeyBitRate, &avgBitrate); 308996bdf620189622005e83b4f1421c4f25b7fa1729Lajos Molnar int32_t maxBitrate = 0; 309046f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate); 309146f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar mOwner->writeInt32(maxBitrate); 309246f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar mOwner->writeInt32(avgBitrate); 309346f80165c595d81dda68f8f3fea27f4fb04937ddLajos Molnar 3094b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 3095b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3096b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 3097b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3098b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3099b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 3100b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 3101b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 3102b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 3103b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 3104b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 3105b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3106b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 3107b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3108b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3109efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeTkhdBox(uint32_t now) { 3110b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("tkhd"); 3111b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Flags = 7 to indicate that the track is enabled, and 3112b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // part of the presentation 3113b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x07); // version=0, flags=7 3114b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 3115b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 3116219f195159f93d627af2b243732e3f9020511a46James Dong mOwner->writeInt32(mTrackId); // track id starts with 1 3117b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 31188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 3119b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 3120b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t tkhdDuration = 3121b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 3122b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 3123b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 3124b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 3125b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // layer 3126b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // alternate group 3127b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 3128b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 3129b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3130b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCompositionMatrix(mRotation); // matrix 313120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3132b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 3133b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 3134b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 3135b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 3136b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 3137b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findInt32(kKeyWidth, &width); 3138b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 3139b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 3140b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3141b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 3142b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 3143b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 3144b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // tkhd 3145b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3146b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3147b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() { 3148b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("vmhd"); 3149b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x01); // version=0, flags=1 3150b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // graphics mode 3151b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // opcolor 3152b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 3153b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 3154b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 3155b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3156b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3157b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() { 3158b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("smhd"); 3159b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3160b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // balance 3161b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 3162b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 3163b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3164b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3165b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() { 3166b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("hdlr"); 3167b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3168b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // component type: should be mhlr 3169b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 3170b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 3171b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 3172b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 3173b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Removing "r" for the name string just makes the string 4 byte aligned 3174b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 3175b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 3176b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3177b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3178efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeMdhdBox(uint32_t now) { 3179b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t trakDurationUs = getDurationUs(); 3180b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdhd"); 3181b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3182b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 3183b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 3184b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mTimeScale); // media timescale 3185b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 3186b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mdhdDuration); // use media timescale 3187b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Language follows the three letter standard ISO-639-2/T 3188b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 'e', 'n', 'g' for "English", for instance. 3189b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Each character is packed as the difference between its ASCII value and 0x60. 3190b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // For "English", these are 00101, 01110, 00111. 3191b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // XXX: Where is the padding bit located: 0x15C7? 3192b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // language code 3193b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 3194b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 3195b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3196b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3197b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() { 3198b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 3gpp2 Spec AMRSampleEntry fields 3199b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("damr"); 3200b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(" "); // vendor: 4 bytes 3201b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 3202b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 3203b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // mode change period 3204b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(1); // frames per sample 3205b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 3206b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3207b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3208b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() { 3209b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // The table index here refers to the sample description index 3210b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // in the sample table entries. 3211b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("url "); 3212b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 3213b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // url 3214b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3215b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3216b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() { 3217b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dref"); 3218b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3219b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count (either url or urn) 3220b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeUrlBox(); 3221b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dref 3222b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3223b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3224b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() { 3225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dinf"); 3226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDrefBox(); 3227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dinf 3228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() { 3231b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 323243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GE(mCodecSpecificDataSize, 5); 3233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Patch avcc's lengthSize field to match the number 3235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // of bytes we use to indicate the size of a nal unit. 3236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong uint8_t *ptr = (uint8_t *)mCodecSpecificData; 3237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 3238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("avcC"); 3239b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3240b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // avcC 3241b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3242b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 32439aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 32449aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kimvoid MPEG4Writer::Track::writeHvccBox() { 32459aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim CHECK(mCodecSpecificData); 32469aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim CHECK_GE(mCodecSpecificDataSize, 5); 32479aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 32489aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim // Patch avcc's lengthSize field to match the number 32499aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim // of bytes we use to indicate the size of a nal unit. 32509aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim uint8_t *ptr = (uint8_t *)mCodecSpecificData; 32519aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 32529aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mOwner->beginBox("hvcC"); 32539aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 32549aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim mOwner->endBox(); // hvcC 32559aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim} 32569aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5eWonsik Kim 3257b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() { 3258b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("d263"); 3259b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // vendor 3260b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 3261b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(10); // level: 10 3262b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // profile: 0 3263b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // d263 3264b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3265b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3266b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square 3267b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() { 3268b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("pasp"); 3269b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // hspacing 3270b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // vspacing 3271b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // pasp 3272b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 3273b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 3274000e18370baae60ffd9f25b509501dd8c26deabfJames Dongint32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { 3275a472613aec322e25891abf5c77bf3f7e3c244920James Dong int64_t trackStartTimeOffsetUs = 0; 3276b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3277b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mStartTimestampUs != moovStartTimeUs) { 327843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong CHECK_GT(mStartTimestampUs, moovStartTimeUs); 3279b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3280b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 3281000e18370baae60ffd9f25b509501dd8c26deabfJames Dong return (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL; 3282000e18370baae60ffd9f25b509501dd8c26deabfJames Dong} 3283000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 3284000e18370baae60ffd9f25b509501dd8c26deabfJames Dongvoid MPEG4Writer::Track::writeSttsBox() { 3285000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mOwner->beginBox("stts"); 3286000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mOwner->writeInt32(0); // version=0, flags=0 3287c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t duration; 3288c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(mSttsTableEntries->get(duration, 1)); 3289c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong duration = htonl(duration); // Back to host byte order 3290c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); 3291c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mSttsTableEntries->write(mOwner); 3292b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stts 3293b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 329420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3295965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::writeCttsBox() { 3296965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong if (mIsAudio) { // ctts is not for audio 3297965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong return; 3298965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 3299965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3300000e18370baae60ffd9f25b509501dd8c26deabfJames Dong // There is no B frame at all 3301000e18370baae60ffd9f25b509501dd8c26deabfJames Dong if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) { 3302000e18370baae60ffd9f25b509501dd8c26deabfJames Dong return; 3303000e18370baae60ffd9f25b509501dd8c26deabfJames Dong } 3304000e18370baae60ffd9f25b509501dd8c26deabfJames Dong 3305965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong // Do not write ctts box when there is no need to have it. 3306c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (mCttsTableEntries->count() == 0) { 3307965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong return; 3308965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong } 3309965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3310a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", 3311c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs); 3312965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3313965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong mOwner->beginBox("ctts"); 3314000e18370baae60ffd9f25b509501dd8c26deabfJames Dong mOwner->writeInt32(0); // version=0, flags=0 3315c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong uint32_t duration; 3316c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong CHECK(mCttsTableEntries->get(duration, 1)); 3317c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong duration = htonl(duration); // Back host byte order 3318c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1); 3319c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCttsTableEntries->write(mOwner); 3320965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong mOwner->endBox(); // ctts 3321965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong} 3322965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong 3323b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() { 3324b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stss"); 3325b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3326c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStssTableEntries->write(mOwner); 3327b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stss 3328b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 332925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 3330b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() { 3331b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsz"); 3332b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3333c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mOwner->writeInt32(0); 3334c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStszTableEntries->write(mOwner); 3335b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsz 3336b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 333720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3338b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() { 3339b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsc"); 3340b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3341c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStscTableEntries->write(mOwner); 3342b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsc 3343b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 334420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3345b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 3346b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 3347b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 3348c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong if (use32BitOffset) { 3349c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mStcoTableEntries->write(mOwner); 3350c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong } else { 3351c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong mCo64TableEntries->write(mOwner); 3352b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 3353b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stco or co64 335420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 335520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 335607b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() { 335707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("udta"); 335807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeGeoDataBox(); 335907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 336007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 336107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 3362e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhangvoid MPEG4Writer::writeHdlr() { 3363e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang beginBox("hdlr"); 3364e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); // Version, Flags 3365e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); // Predefined 3366e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeFourcc("mdta"); 3367e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); // Reserved[0] 3368e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); // Reserved[1] 3369e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); // Reserved[2] 3370e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt8(0); // Name (empty) 3371e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang endBox(); 3372e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang} 3373e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3374e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhangvoid MPEG4Writer::writeKeys() { 3375e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang size_t count = mMetaKeys->countEntries(); 3376e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3377e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang beginBox("keys"); 3378e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); // Version, Flags 3379e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(count); // Entry_count 3380e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang for (size_t i = 0; i < count; i++) { 3381e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang AMessage::Type type; 3382e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang const char *key = mMetaKeys->getEntryNameAt(i, &type); 3383e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang size_t n = strlen(key); 3384e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(n + 8); 3385e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeFourcc("mdta"); 3386e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang write(key, n); // write without the \0 3387e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 3388e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang endBox(); 3389e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang} 3390e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3391e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhangvoid MPEG4Writer::writeIlst() { 3392e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang size_t count = mMetaKeys->countEntries(); 3393e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3394e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang beginBox("ilst"); 3395e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang for (size_t i = 0; i < count; i++) { 3396e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang beginBox(i + 1); // key id (1-based) 3397e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang beginBox("data"); 3398e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang AMessage::Type type; 3399e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang const char *key = mMetaKeys->getEntryNameAt(i, &type); 3400e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang switch (type) { 34017c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang case AMessage::kTypeString: 34027c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang { 34037c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang AString val; 34047c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang CHECK(mMetaKeys->findString(key, &val)); 34057c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(1); // type = UTF8 34067c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(0); // default country/language 34077c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang write(val.c_str(), strlen(val.c_str())); // write without \0 34087c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang break; 34097c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang } 34107c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang 3411e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang case AMessage::kTypeFloat: 3412e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang { 3413e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang float val; 3414e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang CHECK(mMetaKeys->findFloat(key, &val)); 34157c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(23); // type = float32 34167c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(0); // default country/language 3417e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(*reinterpret_cast<int32_t *>(&val)); 3418e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang break; 3419e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 3420e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3421e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang case AMessage::kTypeInt32: 3422e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang { 3423e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang int32_t val; 3424e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang CHECK(mMetaKeys->findInt32(key, &val)); 34257c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(67); // type = signed int32 34267c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(0); // default country/language 3427e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(val); 3428e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang break; 3429e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 3430e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3431e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang default: 3432e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang { 3433e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang ALOGW("Unsupported key type, writing 0 instead"); 34347c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(77); // type = unsigned int32 34357c4820d23b68f748b8dfff3d4bb5b13e9d4811a8Chong Zhang writeInt32(0); // default country/language 3436e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeInt32(0); 3437e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang break; 3438e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 3439e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 3440e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang endBox(); // data 3441e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang endBox(); // key id 3442e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 3443e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang endBox(); // ilst 3444e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang} 3445e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3446e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhangvoid MPEG4Writer::writeMetaBox() { 3447e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang size_t count = mMetaKeys->countEntries(); 3448e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang if (count == 0) { 3449e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang return; 3450e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang } 3451e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 3452e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang beginBox("meta"); 3453e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeHdlr(); 3454e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeKeys(); 3455e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang writeIlst(); 3456e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang endBox(); 3457e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang} 3458e76dba7af9589d9ed7b116eec3a74168a8352925Chong Zhang 345907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 346007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 346107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 346207b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() { 346307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("\xA9xyz"); 346407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong /* 346507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * For historical reasons, any user data start 346607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * with "\0xA9", must be followed by its assoicated 346707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * language code. 3468432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong * 0x0012: text string length 3469432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong * 0x15c7: lang (locale) code: en 347007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 347107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt32(0x001215c7); 347207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLatitude(mLatitudex10000); 347307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLongitude(mLongitudex10000); 347407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt8(0x2F); 347507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 347607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 347707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 347820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 3479