MPEG4Writer.cpp revision 2dec2b5be2056c6d9428897dc672185872d30d17
120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber/* 220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Copyright (C) 2009 The Android Open Source Project 320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * you may not use this file except in compliance with the License. 620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * You may obtain a copy of the License at 720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 1020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Unless required by applicable law or agreed to in writing, software 1120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 1220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * See the License for the specific language governing permissions and 1420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * limitations under the License. 1520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber */ 1620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 17050b28a593350047845a45a14cc5026221ac1620James Dong//#define LOG_NDEBUG 0 18050b28a593350047845a45a14cc5026221ac1620James Dong#define LOG_TAG "MPEG4Writer" 19050b28a593350047845a45a14cc5026221ac1620James Dong#include <utils/Log.h> 20050b28a593350047845a45a14cc5026221ac1620James Dong 2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h> 2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <ctype.h> 2420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h> 2520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 290c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h> 3018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 3103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 34d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h> 35365a963142093a1cd8efdcea76b5f65096a5b115James Dong#include <cutils/properties.h> 3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 3820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 4125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track(MPEG4Writer *owner, const sp<MediaSource> &source); 4220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 44f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t start(int64_t startTimeUs); 4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void stop(); 46a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong void pause(); 4725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 4820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 493b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 50d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 511acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); 5220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 56693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 5720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 58a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 59a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 603b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t mMaxTimeStampUs; 61d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 6220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber struct SampleInfo { 6620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t size; 6720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int64_t timestamp; 6820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 6913aec890216948b0c364f8f92792129d0335f506James Dong List<SampleInfo> mSampleInfos; 70be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 71be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 7213aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 7313aec890216948b0c364f8f92792129d0335f506James Dong List<off_t> mChunkOffsets; 7413aec890216948b0c364f8f92792129d0335f506James Dong 7513aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 7613aec890216948b0c364f8f92792129d0335f506James Dong 7713aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 7813aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 7913aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 8013aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 8113aec890216948b0c364f8f92792129d0335f506James Dong 8213aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 8313aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 8413aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 8513aec890216948b0c364f8f92792129d0335f506James Dong }; 8613aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 8720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 88050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 89365a963142093a1cd8efdcea76b5f65096a5b115James Dong List<int64_t> mChunkDurations; 90050b28a593350047845a45a14cc5026221ac1620James Dong 91be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 92be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 93be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong SttsTableEntry(uint32_t count, uint32_t duration) 94be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong : sampleCount(count), sampleDuration(duration) {} 95be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 96be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 97be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleDuration; 98be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 99be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 100be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 10120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 10220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 103548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 10420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 10525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1063c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 10725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 10820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 10920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void threadEntry(); 11020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 11103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t makeAVCCodecSpecificData( 11203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size); 11313aec890216948b0c364f8f92792129d0335f506James Dong void writeOneChunk(bool isAvc); 114365a963142093a1cd8efdcea76b5f65096a5b115James Dong void logStatisticalData(bool isAudio); 115365a963142093a1cd8efdcea76b5f65096a5b115James Dong void findMinMaxFrameRates(float *minFps, float *maxFps); 116365a963142093a1cd8efdcea76b5f65096a5b115James Dong void findMinMaxChunkDurations(int64_t *min, int64_t *max); 11703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 11820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 11920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 12020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 12120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 12203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#define USE_NALLEN_FOUR 1 12303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 12420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 12520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mFile(fopen(filename, "wb")), 1261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 127a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 128a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 12920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 13013aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 1317837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 13213aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs(500000) { 1330c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mFile != NULL); 13420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 13520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 13630ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 13730ab66297501757d745b9ae10da61adcd891f497Andreas Huber : mFile(fdopen(fd, "wb")), 1381acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 139a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 140a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 14130ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 14213aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 1437837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 14413aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs(500000) { 14530ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(mFile != NULL); 14630ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 14730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 14820111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 14920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 15020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 15120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 15220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 15320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 15420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 15520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 15720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1582dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 15925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track *track = new Track(this, source); 16020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 1612dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 1622dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 16320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 16420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 165a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dongstatus_t MPEG4Writer::startTracks() { 166f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t startTimeUs = systemTime() / 1000; 167a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 168a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 169f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = (*it)->start(startTimeUs); 170a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 171a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 172a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 173a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 174a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 175a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 176a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 177a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 178a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 179a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 180a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 181a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 182a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1832dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 1842dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 1852dec2b5be2056c6d9428897dc672185872d30d17James Dong // 1862dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 1872dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 1882dec2b5be2056c6d9428897dc672185872d30d17James Dong // Currently, lets set to 0.4% for now. 1892dec2b5be2056c6d9428897dc672185872d30d17James Dong 1902dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB, 1912dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 1922dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 4 1932dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 1942dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 1952dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 1962dec2b5be2056c6d9428897dc672185872d30d17James Dong 1972dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 1982dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 1992dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 2002dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024; // 4 KB 2012dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 2022dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 2032dec2b5be2056c6d9428897dc672185872d30d17James Dong 2042dec2b5be2056c6d9428897dc672185872d30d17James Dong if (mMaxFileSizeLimitBytes != 0) { 2052dec2b5be2056c6d9428897dc672185872d30d17James Dong size = mMaxFileSizeLimitBytes * 4 / 1000; 2062dec2b5be2056c6d9428897dc672185872d30d17James Dong } else if (mMaxFileDurationLimitUs != 0) { 2072dec2b5be2056c6d9428897dc672185872d30d17James Dong if (bitRate <= 0) { 2082dec2b5be2056c6d9428897dc672185872d30d17James Dong // We could not estimate the file size since bitRate is not set. 2092dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 2102dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 2112dec2b5be2056c6d9428897dc672185872d30d17James Dong size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000); 2122dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2132dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2142dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 2152dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 2162dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2172dec2b5be2056c6d9428897dc672185872d30d17James Dong 2182dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 2192dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 2202dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 2212dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 2222dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2232dec2b5be2056c6d9428897dc672185872d30d17James Dong 2242dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 2252dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 2262dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 2272dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 2282dec2b5be2056c6d9428897dc672185872d30d17James Dong} 2292dec2b5be2056c6d9428897dc672185872d30d17James Dong 2302dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 23120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 23225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 23320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 23420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2352dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 2362dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 2372dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 2382dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 2392dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 2402dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2412dec2b5be2056c6d9428897dc672185872d30d17James Dong 2422dec2b5be2056c6d9428897dc672185872d30d17James Dong // System property can overwrite the file offset bits parameter 2432dec2b5be2056c6d9428897dc672185872d30d17James Dong char value[PROPERTY_VALUE_MAX]; 2442dec2b5be2056c6d9428897dc672185872d30d17James Dong if (property_get("media.stagefright.record-64bits", value, NULL) 2452dec2b5be2056c6d9428897dc672185872d30d17James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 2462dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 2472dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2482dec2b5be2056c6d9428897dc672185872d30d17James Dong 249065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 250a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 251a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 252a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 253a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return startTracks(); 254a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 255a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 256a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 257a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2587837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 2597837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 2607837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 2617837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 2627837c17063a4c50bc856ba59418516fdab731de7James Dong 26320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 26420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 26520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 26620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 26720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 26820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2697837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 27020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2717837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 2722dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 2732dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 2742dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 2752dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2762dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 2777837c17063a4c50bc856ba59418516fdab731de7James Dong } 2787837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 2797837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 2807837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 2817837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 2827837c17063a4c50bc856ba59418516fdab731de7James Dong 2837837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 2847837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 2857837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 2861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 2871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 2881acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 2891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 2901acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 29125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 292a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong status_t err = startTracks(); 293a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 294a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 29520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 296a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 29725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 29820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 29920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 300a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dongvoid MPEG4Writer::pause() { 301a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mFile == NULL) { 302a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return; 303a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 304a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 305a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 306a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 307a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it)->pause(); 308a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 309a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 310a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 31120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::stop() { 31220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 31320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return; 31420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 31520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 31620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int64_t max_duration = 0; 31720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 31820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 31920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber (*it)->stop(); 32020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3213b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t duration = (*it)->getDurationUs(); 32220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (duration > max_duration) { 32320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber max_duration = duration; 32420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 32520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 32620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3277837c17063a4c50bc856ba59418516fdab731de7James Dong 32820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 3291acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 3301acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 3311acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 3321acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 4, mFile); 3331acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 3341acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset + 8, SEEK_SET); 3351acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 3361acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 3371acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 8, mFile); 3381acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 3397837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 34020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 34120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 3427837c17063a4c50bc856ba59418516fdab731de7James Dong const off_t moovOffset = mOffset; 3437837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 3447837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 3457837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 3467837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 3471acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t timeScale = 1000; 3481acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t duration = max_duration / timeScale; 34920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 35020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 35120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 35220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 35320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 35420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 35520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 3561acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(timeScale); // timescale 3571acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(duration); 3581acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(0x10000); // rate: 1.0 35920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 36020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 36120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 36220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 36320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); // matrix 36420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 36520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 36620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 36720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); 36820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 36920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 37020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 37120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x40000000); 37220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 37320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 37420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 37520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 37620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 37720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 37820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 37920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 38020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 38120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 38220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 38320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 3841acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong (*it)->writeTrackHeader(id, mUse32BitOffset); 38520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 38620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 38720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3887837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 3897837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 3907837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 3917837c17063a4c50bc856ba59418516fdab731de7James Dong 3927837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 3937837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 3947837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 3957837c17063a4c50bc856ba59418516fdab731de7James Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); 3967837c17063a4c50bc856ba59418516fdab731de7James Dong 3977837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 3982dec2b5be2056c6d9428897dc672185872d30d17James Dong fseeko(mFile, mOffset, SEEK_SET); 3997837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 4007837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 4017837c17063a4c50bc856ba59418516fdab731de7James Dong 4027837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 4037837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 4047837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 4057837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4062dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 4072dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 4087837c17063a4c50bc856ba59418516fdab731de7James Dong } 4097837c17063a4c50bc856ba59418516fdab731de7James Dong 4100c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 41120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4127837c17063a4c50bc856ba59418516fdab731de7James Dong fflush(mFile); 41320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fclose(mFile); 41420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mFile = NULL; 415a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 41620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 41720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 41813aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 41913aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 42013aec890216948b0c364f8f92792129d0335f506James Dong return OK; 42113aec890216948b0c364f8f92792129d0335f506James Dong} 42213aec890216948b0c364f8f92792129d0335f506James Dong 42313aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 42413aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 42513aec890216948b0c364f8f92792129d0335f506James Dong} 42613aec890216948b0c364f8f92792129d0335f506James Dong 42713aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 42813aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 42913aec890216948b0c364f8f92792129d0335f506James Dong} 43020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 43113aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 43220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t old_offset = mOffset; 43320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 43420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 43520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1, buffer->range_length(), mFile); 43620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 43720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 43820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 43920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 44020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 44120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 44203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 44303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 44403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 44503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 44603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 44703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 44803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 44903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 45003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 45103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 45203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 45303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 45403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 45503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 45613aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 45730ab66297501757d745b9ae10da61adcd891f497Andreas Huber off_t old_offset = mOffset; 45830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 45930ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 46003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 46103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 46203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t x = length >> 24; 46303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 46403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 16) & 0xff; 46503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 46603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 8) & 0xff; 46703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 46803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = length & 0xff; 46903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 47003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 47130ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(length < 65536); 47230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 47330ab66297501757d745b9ae10da61adcd891f497Andreas Huber uint8_t x = length >> 8; 47430ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 47530ab66297501757d745b9ae10da61adcd891f497Andreas Huber x = length & 0xff; 47630ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 47703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 47830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 47930ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 48030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1, length, mFile); 48130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 48203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 48303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOffset += length + 4; 48403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 48530ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset += length + 2; 48603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 48730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 48830ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 48930ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 49030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 4917837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 4927837c17063a4c50bc856ba59418516fdab731de7James Dong const void *ptr, size_t size, size_t nmemb, FILE *stream) { 4937837c17063a4c50bc856ba59418516fdab731de7James Dong 4947837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 4957837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 4961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 4971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 4987837c17063a4c50bc856ba59418516fdab731de7James Dong for (List<off_t>::iterator it = mBoxes.begin(); 4997837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 5007837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 5017837c17063a4c50bc856ba59418516fdab731de7James Dong } 5027837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 5037837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream); 5047837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 5057837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 5067837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 5077837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 5087837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 5097837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 5107837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 5117837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 5127837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 5137837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 5147837c17063a4c50bc856ba59418516fdab731de7James Dong } 5157837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 5167837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 5177837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 5187837c17063a4c50bc856ba59418516fdab731de7James Dong } 5197837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 5207837c17063a4c50bc856ba59418516fdab731de7James Dong} 5217837c17063a4c50bc856ba59418516fdab731de7James Dong 52220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 5230c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 52420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5257837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 5267837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 52720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 53020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 53120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 5330c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 53420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t offset = *--mBoxes.end(); 53620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 53720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5387837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 5397837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 5407837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 5417837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 5427837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, offset, SEEK_SET); 5437837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 5447837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 5457837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 5467837c17063a4c50bc856ba59418516fdab731de7James Dong } 54720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 54820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 54920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 5507837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 1, mFile); 55120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 55220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 55420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 5557837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 2, mFile); 55620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 55720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 55920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 5607837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 4, mFile); 56120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 56220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 56320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 56420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 5657837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 8, mFile); 56620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 56720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 56820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 56920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 5707837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, n + 1, mFile); 57120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 57220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 57320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 5740c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 5757837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, 4, mFile); 57620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 57720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 57820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 5797837c17063a4c50bc856ba59418516fdab731de7James Dong write(data, 1, size, mFile); 58020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 58120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 582d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 583d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 584d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 585d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 586d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 587d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 588956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 589d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 590d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 591d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 592d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 593d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes); 594d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 595d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 596d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 597d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 598d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 599d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 600d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 601d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 602d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 603d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 604d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 605d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 606d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 607d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 608d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 609d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 610d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 61125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 61225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 61325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 61425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 61525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 61625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 61725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 61825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 61925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 62025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 62125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 62225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 62325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 624f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 625f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 626f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 6273c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 628065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 629f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 630f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 6313c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 6323c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 6333c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 634f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 635f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("getStartTimestampUs: %lld", mStartTimestampUs); 6363c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 6373c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 6383c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 6393c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 64058ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 64158ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 64258ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 64358ae9c530247668f8af36e30d228c716c226b3d4James Dong} 64458ae9c530247668f8af36e30d228c716c226b3d4James Dong 64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 64825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber MPEG4Writer *owner, const sp<MediaSource> &source) 64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 65025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 65120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 65220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 653a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 654a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 6553b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mMaxTimeStampUs(0), 656956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 657be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 65820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 65925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 660548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 66125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS(false) { 66220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 66320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 66420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 66520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 66720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 66920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 67020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 67220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 673f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongstatus_t MPEG4Writer::Track::start(int64_t startTimeUs) { 674a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 675a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 676a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 677a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 678a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 67925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 680f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 681f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 682f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 68325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 68425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 68525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 68625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 68720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 68820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 68920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 69020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 69120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 6933b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mMaxTimeStampUs = 0; 69425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 695956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 69620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 69925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 70025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 70120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 70220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 703a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dongvoid MPEG4Writer::Track::pause() { 704a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 705a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 706a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::stop() { 70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 70920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return; 71020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 71120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 71320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 71520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 71620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource->stop(); 71820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 71920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 72025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 72125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 72225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 72325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 72420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 72520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 72620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 72720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 72820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber track->threadEntry(); 72920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 73020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return NULL; 73120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 73220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 733548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber#include <ctype.h> 734548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huberstatic void hexdump(const void *_data, size_t size) { 735548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber const uint8_t *data = (const uint8_t *)_data; 736548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t offset = 0; 737548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber while (offset < size) { 738548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("0x%04x ", offset); 739548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 740548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t n = size - offset; 741548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (n > 16) { 742548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber n = 16; 743548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 744548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 745548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < 16; ++i) { 746548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (i == 8) { 747548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 748548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 749548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 750548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (offset + i < size) { 751548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%02x ", data[offset + i]); 752548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 753548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 754548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 755548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 756548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 757548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 758548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 759548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < n; ++i) { 760548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (isprint(data[offset + i])) { 761548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%c", data[offset + i]); 762548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 763548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("."); 764548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 765548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 766548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 767548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("\n"); 768548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 769548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber offset += 16; 770548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 771548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber} 772548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 773548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 77403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 77503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 776548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber // hexdump(data, size); 777548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 77803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 779548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 78003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 78103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 78203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 78303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { 784548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Must start with a start code"); 78503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 78603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 78703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 78803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t picParamOffset = 4; 78903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber while (picParamOffset + 3 < size 79003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) { 79103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber ++picParamOffset; 79203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 79303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 79403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (picParamOffset + 3 >= size) { 795548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Could not find start-code for pictureParameterSet"); 79603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 79703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 79803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 79903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t seqParamSetLength = picParamOffset - 4; 80003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t picParamSetLength = size - picParamOffset - 4; 80103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 80203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = 80303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2; 80403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 80503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 80603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 80703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[0] = 1; 80803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[1] = 0x42; // profile 80903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[2] = 0x80; 81003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[3] = 0x1e; // level 81103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 81203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 81303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 3; // length size == 4 bytes 81403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 81503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 1; // length size == 2 bytes 81603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 81703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 81803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[5] = 0xe0 | 1; 81903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[6] = seqParamSetLength >> 8; 82003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[7] = seqParamSetLength & 0xff; 82103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(&header[8], &data[4], seqParamSetLength); 82203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header += 8 + seqParamSetLength; 82303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[0] = 1; 82403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[1] = picParamSetLength >> 8; 82503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[2] = picParamSetLength & 0xff; 82603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength); 82703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 82803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 82903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 83003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::threadEntry() { 83220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> meta = mSource->getFormat(); 83320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 83420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber meta->findCString(kKeyMIMEType, &mime); 835050b28a593350047845a45a14cc5026221ac1620James Dong bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 836050b28a593350047845a45a14cc5026221ac1620James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 83730ab66297501757d745b9ae10da61adcd891f497Andreas Huber bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 838956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong bool is_audio = !strncasecmp(mime, "audio/", 6); 83930ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 84013aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 84113aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 84213aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 84313aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 844be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong int64_t lastTimestamp = 0; // Timestamp of the previous sample 845be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong int64_t lastDuration = 0; // Time spacing between the previous two samples 846be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 847be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 848a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 849d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 85020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 85220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber while (!mDone && mSource->read(&buffer) == OK) { 85320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 85420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 85520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 85613aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 85720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 85820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 85920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 860a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 861a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 862a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 863a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 864a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 865a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 866a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 867a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 868a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 86930ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 87030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 87103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 87203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 87303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 874548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 875548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 87603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (is_avc) { 87703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 87803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 87903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 88003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 881be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 88203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } else if (is_mpeg4) { 88303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 88403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 88503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 88603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 88703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 88803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 88930ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 89030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 89130ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 89230ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 89330ab66297501757d745b9ae10da61adcd891f497Andreas Huber 894548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 89530ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 896548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else if (!mGotAllCodecSpecificData && 897548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { 89803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // The TI mpeg4 encoder does not properly set the 89903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // codec-specific-data flag. 90030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 90120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const uint8_t *data = 90220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 90320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 90420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const size_t size = buffer->range_length(); 90520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 90620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t offset = 0; 90720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber while (offset + 3 < size) { 90820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (data[offset] == 0x00 && data[offset + 1] == 0x00 90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) { 91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber break; 91120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 91220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 91320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ++offset; 91420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 91520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9160c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber // CHECK(offset + 3 < size); 917bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber if (offset + 3 >= size) { 918bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber // XXX assume the entire first chunk of data is the codec specific 919bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber // data. 920bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber offset = size; 921bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber } 92220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificDataSize = offset; 92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = malloc(offset); 92520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber memcpy(mCodecSpecificData, data, offset); 92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->set_range(buffer->range_offset() + offset, size - offset); 92803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 92903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (size == offset) { 93003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->release(); 93103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer = NULL; 93203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 93303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber continue; 93403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 935548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 936548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 937548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else if (!mGotAllCodecSpecificData && is_avc && count < 3) { 93803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // The TI video encoder does not flag codec specific data 93903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // as such and also splits up SPS and PPS across two buffers. 94003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 94103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data = 94203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 94303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 94403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t size = buffer->range_length(); 94503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 94603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber CHECK(count == 2 || mCodecSpecificData == NULL); 94703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 94803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t offset = mCodecSpecificDataSize; 94903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize += size + 4; 95003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = 95103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber realloc(mCodecSpecificData, mCodecSpecificDataSize); 95203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 95303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy((uint8_t *)mCodecSpecificData + offset, 95403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber "\x00\x00\x00\x01", 4); 95503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 95603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size); 95703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 95803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->release(); 95903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer = NULL; 96003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 96103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (count == 2) { 96203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber void *tmp = mCodecSpecificData; 96303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size = mCodecSpecificDataSize; 96403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = NULL; 96503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = 0; 96603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 96703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 96803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)tmp, size); 96903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber free(tmp); 97003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber tmp = NULL; 971be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 972548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 973548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 97403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 97503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 97603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber continue; 97720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 97820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 979a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mGotAllCodecSpecificData) { 980a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mGotAllCodecSpecificData = true; 981a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 982a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 983d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 984d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 985d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 986d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 987d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 988d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 989d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 990d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 991d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 992d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 993d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (is_avc) StripStartcode(copy); 994e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 99520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber SampleInfo info; 99603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber info.size = is_avc 99703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 998d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 4 99903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 1000d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 2 100103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 1002d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong : copy->range_length(); 1003050b28a593350047845a45a14cc5026221ac1620James Dong 1004d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 1005d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mEstimatedTrackSizeBytes += info.size; 1006d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 1007d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1008d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1009d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1010d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 1011d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1012d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1013d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1014d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1015050b28a593350047845a45a14cc5026221ac1620James Dong 1016d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 1017d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1018d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 101948c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber int64_t timestampUs; 1020d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 1021d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1022d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 10233c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong if (mSampleInfos.empty()) { 1024f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 1025f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 10263c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 102748c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 1028a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 1029a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration); 1030a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 1031a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1032a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1033a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 1034a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong LOGV("time stamp: %lld and previous paused duration %lld", 1035a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs, previousPausedDurationUs); 10363b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber if (timestampUs > mMaxTimeStampUs) { 10373b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mMaxTimeStampUs = timestampUs; 10383b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 10393b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 104048c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber // Our timestamp is in ms. 104148c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber info.timestamp = (timestampUs + 500) / 1000; 104220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSampleInfos.push_back(info); 1043be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSampleInfos.size() > 2) { 1044be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (lastDuration != info.timestamp - lastTimestamp) { 1045be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong SttsTableEntry sttsEntry(sampleCount, lastDuration); 1046be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 1047be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 1048be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1049be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 1050be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1051be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1052be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1053be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSampleInfos.size() >= 2 && previousSampleSize != info.size) { 1054be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 1055be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1056be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong previousSampleSize = info.size; 1057be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1058be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong lastDuration = info.timestamp - lastTimestamp; 1059be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong lastTimestamp = info.timestamp; 106020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1061d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 1062d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong mStssTableEntries.push_back(mSampleInfos.size()); 1063d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 1064d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 106558ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 106658ae9c530247668f8af36e30d228c716c226b3d4James Dong off_t offset = is_avc? mOwner->addLengthPrefixedSample_l(copy) 106758ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 106858ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 106958ae9c530247668f8af36e30d228c716c226b3d4James Dong mChunkOffsets.push_back(offset); 107058ae9c530247668f8af36e30d228c716c226b3d4James Dong } 107158ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 107258ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 107358ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 107458ae9c530247668f8af36e30d228c716c226b3d4James Dong } 107513aec890216948b0c364f8f92792129d0335f506James Dong 107613aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 107713aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 107813aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(++nChunks, 1, 1); 107913aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 108013aec890216948b0c364f8f92792129d0335f506James Dong writeOneChunk(is_avc); 108113aec890216948b0c364f8f92792129d0335f506James Dong } else { 108213aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 108313aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 108413aec890216948b0c364f8f92792129d0335f506James Dong } else { 108513aec890216948b0c364f8f92792129d0335f506James Dong if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 108613aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 1087365a963142093a1cd8efdcea76b5f65096a5b115James Dong mChunkDurations.push_back(timestampUs - chunkTimestampUs); 108813aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 108913aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 109013aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 109113aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, 109213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size(), 1); 109313aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 109413aec890216948b0c364f8f92792129d0335f506James Dong } 109513aec890216948b0c364f8f92792129d0335f506James Dong writeOneChunk(is_avc); 109613aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 109713aec890216948b0c364f8f92792129d0335f506James Dong } 109813aec890216948b0c364f8f92792129d0335f506James Dong } 109913aec890216948b0c364f8f92792129d0335f506James Dong } 110013aec890216948b0c364f8f92792129d0335f506James Dong 110120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 110225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 1103f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong if (mSampleInfos.empty()) { 1104f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_STOP_PREMATURELY, 0); 1105f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 1106be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 110713aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 110858ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 110958ae9c530247668f8af36e30d228c716c226b3d4James Dong StscTableEntry stscEntry(1, mSampleInfos.size(), 1); 111058ae9c530247668f8af36e30d228c716c226b3d4James Dong mStscTableEntries.push_back(stscEntry); 111158ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 111213aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 111313aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1); 111413aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 111513aec890216948b0c364f8f92792129d0335f506James Dong writeOneChunk(is_avc); 111613aec890216948b0c364f8f92792129d0335f506James Dong } 111713aec890216948b0c364f8f92792129d0335f506James Dong 1118be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 1119be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 1120be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 1121be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSampleInfos.size() == 1) { 1122be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong lastDuration = 0; // A single sample's duration 1123be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1124be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 1125be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1126be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong SttsTableEntry sttsEntry(sampleCount, lastDuration); 1127be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 112825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 1129956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s", 1130956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video"); 1131365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1132365a963142093a1cd8efdcea76b5f65096a5b115James Dong logStatisticalData(is_audio); 1133365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1134365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1135365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::findMinMaxFrameRates(float *minFps, float *maxFps) { 1136365a963142093a1cd8efdcea76b5f65096a5b115James Dong int32_t minSampleDuration = 0x7FFFFFFF; 1137365a963142093a1cd8efdcea76b5f65096a5b115James Dong int32_t maxSampleDuration = 0; 1138365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1139365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != mSttsTableEntries.end(); ++it) { 1140365a963142093a1cd8efdcea76b5f65096a5b115James Dong int32_t sampleDuration = static_cast<int32_t>(it->sampleDuration); 1141365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (sampleDuration > maxSampleDuration) { 1142365a963142093a1cd8efdcea76b5f65096a5b115James Dong maxSampleDuration = sampleDuration; 1143365a963142093a1cd8efdcea76b5f65096a5b115James Dong } else if (sampleDuration < minSampleDuration) { 1144365a963142093a1cd8efdcea76b5f65096a5b115James Dong minSampleDuration = sampleDuration; 1145365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1146365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1147365a963142093a1cd8efdcea76b5f65096a5b115James Dong CHECK(minSampleDuration != 0 && maxSampleDuration != 0); 1148365a963142093a1cd8efdcea76b5f65096a5b115James Dong *minFps = 1000.0 / maxSampleDuration; 1149365a963142093a1cd8efdcea76b5f65096a5b115James Dong *maxFps = 1000.0 / minSampleDuration; 1150365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1151365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1152365a963142093a1cd8efdcea76b5f65096a5b115James Dong// Don't count the last duration 1153365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) { 1154365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1155365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunkDuration = duration; 1156365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t maxChunkDuration = duration; 1157365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (mChunkDurations.size() > 1) { 1158365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<int64_t>::iterator it = mChunkDurations.begin(); 1159365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != --mChunkDurations.end(); ++it) { 1160365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (minChunkDuration > (*it)) { 1161365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunkDuration = (*it); 1162365a963142093a1cd8efdcea76b5f65096a5b115James Dong } else if (maxChunkDuration < (*it)) { 1163365a963142093a1cd8efdcea76b5f65096a5b115James Dong maxChunkDuration = (*it); 1164365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1165365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1166365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1167365a963142093a1cd8efdcea76b5f65096a5b115James Dong *min = minChunkDuration; 1168365a963142093a1cd8efdcea76b5f65096a5b115James Dong *max = maxChunkDuration; 1169365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1170365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1171365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::logStatisticalData(bool isAudio) { 1172365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (mMaxTimeStampUs <= 0 || mSampleInfos.empty()) { 1173365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("nothing is recorded"); 1174365a963142093a1cd8efdcea76b5f65096a5b115James Dong return; 1175365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1176365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1177365a963142093a1cd8efdcea76b5f65096a5b115James Dong bool collectStats = false; 1178365a963142093a1cd8efdcea76b5f65096a5b115James Dong char value[PROPERTY_VALUE_MAX]; 1179365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (property_get("media.stagefright.record-stats", value, NULL) 1180365a963142093a1cd8efdcea76b5f65096a5b115James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 1181365a963142093a1cd8efdcea76b5f65096a5b115James Dong collectStats = true; 1182365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1183365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1184365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (collectStats) { 1185365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (isAudio) { 1186365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("audio track - duration %lld us", mMaxTimeStampUs); 1187365a963142093a1cd8efdcea76b5f65096a5b115James Dong } else { 1188365a963142093a1cd8efdcea76b5f65096a5b115James Dong float fps = (mSampleInfos.size() * 1000000.0) / mMaxTimeStampUs; 1189365a963142093a1cd8efdcea76b5f65096a5b115James Dong float minFps; 1190365a963142093a1cd8efdcea76b5f65096a5b115James Dong float maxFps; 1191365a963142093a1cd8efdcea76b5f65096a5b115James Dong findMinMaxFrameRates(&minFps, &maxFps); 1192365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("video track - duration %lld us", mMaxTimeStampUs); 1193365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f", 1194365a963142093a1cd8efdcea76b5f65096a5b115James Dong minFps, fps, maxFps); 1195365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1196365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1197365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t totalBytes = 0; 1198365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 1199365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != mSampleInfos.end(); ++it) { 1200365a963142093a1cd8efdcea76b5f65096a5b115James Dong totalBytes += it->size; 1201365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1202365a963142093a1cd8efdcea76b5f65096a5b115James Dong float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs; 1203365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("avg bit rate (bps): %.2f", bitRate); 1204365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1205365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1206365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (duration != 0) { // If interleaving is enabled 1207365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunk, maxChunk; 1208365a963142093a1cd8efdcea76b5f65096a5b115James Dong findMinMaxChunkDurations(&minChunk, &maxChunk); 1209365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld", 1210365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunk, duration, maxChunk); 1211365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1212365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 121313aec890216948b0c364f8f92792129d0335f506James Dong} 121413aec890216948b0c364f8f92792129d0335f506James Dong 121513aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::Track::writeOneChunk(bool isAvc) { 121613aec890216948b0c364f8f92792129d0335f506James Dong mOwner->lock(); 121713aec890216948b0c364f8f92792129d0335f506James Dong for (List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 121813aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkSamples.end(); ++it) { 121913aec890216948b0c364f8f92792129d0335f506James Dong off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it) 122013aec890216948b0c364f8f92792129d0335f506James Dong : mOwner->addSample_l(*it); 122113aec890216948b0c364f8f92792129d0335f506James Dong if (it == mChunkSamples.begin()) { 122213aec890216948b0c364f8f92792129d0335f506James Dong mChunkOffsets.push_back(offset); 122313aec890216948b0c364f8f92792129d0335f506James Dong } 122413aec890216948b0c364f8f92792129d0335f506James Dong } 122513aec890216948b0c364f8f92792129d0335f506James Dong mOwner->unlock(); 122613aec890216948b0c364f8f92792129d0335f506James Dong while (!mChunkSamples.empty()) { 122713aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 122813aec890216948b0c364f8f92792129d0335f506James Dong (*it)->release(); 122913aec890216948b0c364f8f92792129d0335f506James Dong (*it) = NULL; 123013aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.erase(it); 123113aec890216948b0c364f8f92792129d0335f506James Dong } 123213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 123320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 123420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 12353b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 12363b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber return mMaxTimeStampUs; 123720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 123820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1239d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 1240d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 1241d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1242d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 12431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader( 12441acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t trackID, bool use32BitOffset) { 124520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 124620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 12470c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 124820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 124920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool is_audio = !strncasecmp(mime, "audio/", 6); 12501acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t timeScale = 1000; 12511acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t duration = getDurationUs() / timeScale; 125220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 125320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 125420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 125520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 125620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 125720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 12581acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Flags = 7 to indicate that the track is enabled, and 12591acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // part of the presentation 12601acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x07); // version=0, flags=7 126120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 126220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 126320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 126420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 12651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(duration); 126620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 126720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 126820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 126920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 127020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(is_audio ? 0x100 : 0); // volume 127120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 127220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 127320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); // matrix 127420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 127520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 127620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 127720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); 127820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 127920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 128020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 128120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x40000000); 128220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 128320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (is_audio) { 128420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 128520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 128620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 128720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 128820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 128920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 12900c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 129120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1292050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 1293050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 129420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 129520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 129620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1297f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 1298f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong if (mStartTimestampUs != moovStartTimeUs) { 12993c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("edts"); 13003c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("elst"); 13011acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 13021acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(2); // never ends with an empty list 1303f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t durationMs = 1304f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong (mStartTimestampUs - moovStartTimeUs) / 1000; 1305f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->writeInt32(durationMs); // edit duration 1306956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mOwner->writeInt32(-1); // empty edit box to signal starting time offset 13071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // x1 rate 13081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(duration); 13091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); 13101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); 13113c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 13123c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 13133c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 13143c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 131520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 131620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 131720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 131820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 131920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 132020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 13211acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(timeScale); // timescale 13221acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(duration); // duration 13231acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Language follows the three letter standard ISO-639-2/T 13241acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // 'e', 'n', 'g' for "English", for instance. 13251acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Each character is packed as the difference between its ASCII value and 0x60. 13261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // For "English", these are 00101, 01110, 00111. 13271acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // XXX: Where is the padding bit located: 0x15C7? 13281acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(0); // language code 132920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 133020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 133120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 133220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 133320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 1334050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // component type: should be mhlr 1335050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeFourcc(is_audio ? "soun" : "vide"); // component subtype 133620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 133720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 133820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 13391acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Removing "r" for the name string just makes the string 4 byte aligned 13401acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeCString(is_audio ? "SoundHandle": "VideoHandle"); // name 134120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 134220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 134320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 134420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (is_audio) { 134520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 134620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 134720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 134820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 134920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 135020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 135120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 13521acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x01); // version=0, flags=1 135320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 135420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 135520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 135620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 135720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 135820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 1359050b28a593350047845a45a14cc5026221ac1620James Dong 1360050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dinf"); 1361050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dref"); 1362050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 13631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // entry count (either url or urn) 13641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // The table index here refers to the sample description index 13651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // in the sample table entries. 1366050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("url "); 13671acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 1368050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // url 1369050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dref 1370050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dinf 1371050b28a593350047845a45a14cc5026221ac1620James Dong 137220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 137320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 137420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 137520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 137620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 137720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (is_audio) { 137825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 137918291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 138025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 138118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 138225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 1383050b28a593350047845a45a14cc5026221ac1620James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1384050b28a593350047845a45a14cc5026221ac1620James Dong fourcc = "mp4a"; 138525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 138625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 138725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 138825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 138925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 139025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 139120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 139220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 1393050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x1); // data ref index 139420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 139520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 1396050b28a593350047845a45a14cc5026221ac1620James Dong int32_t nChannels; 1397050b28a593350047845a45a14cc5026221ac1620James Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 1398050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(nChannels); // channel count 139920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 140020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 140120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 140220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 140320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 140420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 14050c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 140620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 140720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 1408050b28a593350047845a45a14cc5026221ac1620James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1409050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("esds"); 1410050b28a593350047845a45a14cc5026221ac1620James Dong 1411050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 1412050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x03); // ES_DescrTag 1413050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 1414050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x0000);// ES_ID 1415050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); 1416050b28a593350047845a45a14cc5026221ac1620James Dong 1417050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 1418050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 1419050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 1420050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x15); // streamType AudioStream 1421050b28a593350047845a45a14cc5026221ac1620James Dong 1422050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x03); // XXX 1423050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); // buffer size 24-bit 1424050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // max bit rate 1425050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // avg bit rate 1426050b28a593350047845a45a14cc5026221ac1620James Dong 1427050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 1428050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(mCodecSpecificDataSize); 1429050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1430050b28a593350047845a45a14cc5026221ac1620James Dong 1431050b28a593350047845a45a14cc5026221ac1620James Dong static const uint8_t kData2[] = { 1432050b28a593350047845a45a14cc5026221ac1620James Dong 0x06, // SLConfigDescriptorTag 1433050b28a593350047845a45a14cc5026221ac1620James Dong 0x01, 1434050b28a593350047845a45a14cc5026221ac1620James Dong 0x02 1435050b28a593350047845a45a14cc5026221ac1620James Dong }; 1436050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(kData2, sizeof(kData2)); 1437050b28a593350047845a45a14cc5026221ac1620James Dong 1438050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // esds 1439050b28a593350047845a45a14cc5026221ac1620James Dong } 144020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 144120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 144218291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 144320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 144418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 144520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 144630ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 144730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 144820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 144925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 14500c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 145120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 145220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 145320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 145420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 14551acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(1); // data ref index 145620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 145720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 145820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 145920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 146020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 146120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 146220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 146320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 146420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 14650c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 146620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 146720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 146820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 146920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 147020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 147120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 147220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 147320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 147420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 147520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 147620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 14770c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 147820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 147918291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 148020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 148120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 148220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 148320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 148420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 148520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 148620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 148720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 148820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 148920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 149020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 149120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 149220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 149320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 149420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 149520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 149620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 149720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 149820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 149920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 1500050b28a593350047845a45a14cc5026221ac1620James Dong 150120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 150220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 150320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 150420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 150520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 150620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 150720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 150820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 150920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 151020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 151120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 151220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 151320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 151418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 151520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 151620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 151720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 151820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 151920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 152020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 152120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 152220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 152330ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 152430ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 152530ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 152630ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 152720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 152830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 15291acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox("pasp"); 15301acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // This is useful if the pixel is not square 15311acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // hspacing 15321acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // vspacing 15331acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // pasp 153430ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 153520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 153620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 153720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 153820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 153920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 1540be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(mSttsTableEntries.size()); 1541be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1542be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSttsTableEntries.end(); ++it) { 1543be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleCount); 1544be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleDuration); 154520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 154620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 154720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1548050b28a593350047845a45a14cc5026221ac1620James Dong if (!is_audio) { 1549050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("stss"); 1550050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 1551050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames 1552050b28a593350047845a45a14cc5026221ac1620James Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 1553050b28a593350047845a45a14cc5026221ac1620James Dong it != mStssTableEntries.end(); ++it) { 1554050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(*it); 1555050b28a593350047845a45a14cc5026221ac1620James Dong } 1556050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // stss 1557050b28a593350047845a45a14cc5026221ac1620James Dong } 1558050b28a593350047845a45a14cc5026221ac1620James Dong 155920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 156020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 1561be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1562be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SampleInfo>::iterator it = mSampleInfos.begin(); 1563be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->size); // default sample size 1564be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1565be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(0); 1566be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 156720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(mSampleInfos.size()); 1568be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (!mSamplesHaveSameSize) { 1569be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 1570be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSampleInfos.end(); ++it) { 1571be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32((*it).size); 1572be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 157320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 157420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 157520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 157620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 157720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 157813aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mStscTableEntries.size()); 157913aec890216948b0c364f8f92792129d0335f506James Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 158013aec890216948b0c364f8f92792129d0335f506James Dong it != mStscTableEntries.end(); ++it) { 158113aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->firstChunk); 158213aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->samplesPerChunk); 158313aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->sampleDescriptionId); 158420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 158520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 15861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 158720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 158813aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mChunkOffsets.size()); 158913aec890216948b0c364f8f92792129d0335f506James Dong for (List<off_t>::iterator it = mChunkOffsets.begin(); 159013aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkOffsets.end(); ++it) { 15911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (use32BitOffset) { 15921acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 15931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 15941acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt64((*it)); 15951acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 159620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 159720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // co64 159820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 159920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 16001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // minf 160120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 160220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 160320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 160420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 160520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 1606