MPEG4Writer.cpp revision acd234bba9f048971d66890009eeff9a8db94be3
120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber/* 220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Copyright (C) 2009 The Android Open Source Project 320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * you may not use this file except in compliance with the License. 620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * You may obtain a copy of the License at 720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 1020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Unless required by applicable law or agreed to in writing, software 1120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 1220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * See the License for the specific language governing permissions and 1420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * limitations under the License. 1520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber */ 1620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 17050b28a593350047845a45a14cc5026221ac1620James Dong//#define LOG_NDEBUG 0 18050b28a593350047845a45a14cc5026221ac1620James Dong#define LOG_TAG "MPEG4Writer" 19050b28a593350047845a45a14cc5026221ac1620James Dong#include <utils/Log.h> 20050b28a593350047845a45a14cc5026221ac1620James Dong 2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h> 2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h> 24a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/prctl.h> 25a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/resource.h> 2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 2920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 300c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h> 3118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 3203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 35d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h> 3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 3819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 411f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL; 423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 445b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong 455b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// Using longer adjustment period to suppress fluctuations in 465b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// the audio encoding paths 475b6a01e65aa4129a9226667536d1bc1dad5980d8James Dongstatic const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL; // 10 minutes 483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 4920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 5020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 5125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track(MPEG4Writer *owner, const sp<MediaSource> &source); 528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 5320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 5637187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 5737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 5825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 5920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 603b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 61d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 621acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); 631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 671f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addChunkOffset(off_t offset); 68dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong status_t dump(int fd, const Vector<String16>& args) const; 6920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 7120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 7220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 73693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 7420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 75a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 76a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 80c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 81e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 82e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // For realtime applications, we need to adjust the media clock 83e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // for video track based on the audio media clock 84e259531ce59ab1f31de5a23124b22536f6a5a767James Dong bool mIsRealTimeRecording; 85e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t mMaxTimeStampUs; 86d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t mMdatSizeBytes; 888f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 8920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 9120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // mNumSamples is used to track how many samples in mSampleSizes List. 93ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // This is to reduce the cost associated with mSampleSizes.size() call, 94ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // since it is O(n). Ideally, the fix should be in List class. 95ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong size_t mNumSamples; 968644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t> mSampleSizes; 97be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 98be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 9913aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 1001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStcoTableEntries; 10213aec890216948b0c364f8f92792129d0335f506James Dong List<off_t> mChunkOffsets; 10313aec890216948b0c364f8f92792129d0335f506James Dong 1041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStscTableEntries; 10513aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 10613aec890216948b0c364f8f92792129d0335f506James Dong 10713aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 10813aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 10913aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 11013aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 11113aec890216948b0c364f8f92792129d0335f506James Dong 11213aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 11313aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 11413aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 11513aec890216948b0c364f8f92792129d0335f506James Dong }; 11613aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 11720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStssTableEntries; 119050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 120050b28a593350047845a45a14cc5026221ac1620James Dong 1211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumSttsTableEntries; 122be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 123be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry(uint32_t count, uint32_t durationUs) 1258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong : sampleCount(count), sampleDurationUs(durationUs) {} 126be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 127be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 1288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong uint32_t sampleDurationUs; 129be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 130be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 131be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 1333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 1343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 1353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 1363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 1383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 1393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 1403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 1413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 14720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 148548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 14993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 15020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 15125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1523c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 15393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 15493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 15525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 156872a481558350634a3fd5cb67939de288af00ecbJames Dong // Has the media time adjustment for video started? 157872a481558350634a3fd5cb67939de288af00ecbJames Dong bool mIsMediaTimeAdjustmentOn; 158872a481558350634a3fd5cb67939de288af00ecbJames Dong // The time stamp when previous media time adjustment period starts 159872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustTimestampUs; 160872a481558350634a3fd5cb67939de288af00ecbJames Dong // Number of vidoe frames whose time stamp may be adjusted 161872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mMediaTimeAdjustNumFrames; 162872a481558350634a3fd5cb67939de288af00ecbJames Dong // The sample number when previous meida time adjustmnet period starts 163872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustSample; 164872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumulated drift time within a period of 165872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 166872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mTotalDriftTimeToAdjustUs; 167872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumalated drift time since the start of the recording 168872a481558350634a3fd5cb67939de288af00ecbJames Dong // excluding the current time adjustment period 169872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevTotalAccumDriftTimeUs; 170872a481558350634a3fd5cb67939de288af00ecbJames Dong 171872a481558350634a3fd5cb67939de288af00ecbJames Dong // Update the audio track's drift information. 172872a481558350634a3fd5cb67939de288af00ecbJames Dong void updateDriftTime(const sp<MetaData>& meta); 173872a481558350634a3fd5cb67939de288af00ecbJames Dong 174872a481558350634a3fd5cb67939de288af00ecbJames Dong // Adjust the time stamp of the video track according to 175872a481558350634a3fd5cb67939de288af00ecbJames Dong // the drift time information from the audio track. 176872a481558350634a3fd5cb67939de288af00ecbJames Dong void adjustMediaTime(int64_t *timestampUs); 177872a481558350634a3fd5cb67939de288af00ecbJames Dong 17820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 17937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 18020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 1823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 1833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t makeAVCCodecSpecificData( 18503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size); 1863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t copyAVCCodecSpecificData( 1873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 1883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t parseAVCCodecSpecificData( 1893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 190215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 191215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 192faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 19393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 19403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 19519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 19619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 197c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 198c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 199c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 200c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 201c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 202c059860c73678a202bfa33062723e8f82fb779d9James Dong 203690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 204690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 205aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong int32_t mRotation; 206690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void updateTrackSizeEstimate(); 2081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStscTableEntry(size_t chunkId, size_t sampleId); 2091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStssTableEntry(size_t sampleId); 2101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs); 2111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 21220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 21420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 21520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21620111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 21720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mFile(fopen(filename, "wb")), 218b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2191acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 220a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 221a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 222a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 22320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 22413aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2257837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 226f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 2270c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mFile != NULL); 22820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 22920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 23030ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 23130ab66297501757d745b9ae10da61adcd891f497Andreas Huber : mFile(fdopen(fd, "wb")), 232b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2331acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 234a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 235a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 236a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 23730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 23813aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2397837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 240f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 24130ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(mFile != NULL); 24230ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 24330ab66297501757d745b9ae10da61adcd891f497Andreas Huber 24420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 24520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 24620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2471f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong while (!mTracks.empty()) { 2481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong List<Track *>::iterator it = mTracks.begin(); 24920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 2501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong (*it) = NULL; 2511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mTracks.erase(it); 25220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 25320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 25420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 25520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 256dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 257dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 258dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 259dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 260dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 261dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 262dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 263dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 264dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 265dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 266dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 267dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 268dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 269dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 270dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 271dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 272dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 273dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 274dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) const { 275dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 276dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 277dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 278dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 279dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 280dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 281dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 282dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 283dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 284dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 285dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 286dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 2872dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 28825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track *track = new Track(this, source); 28920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 2902dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 2912dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 29320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 29493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 295a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 296a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 29793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 298a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 299a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 300a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 301a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 302a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 303a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 304a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 305a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 306a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 307a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 308a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 309a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 310a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3112dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 3122dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 3132dec2b5be2056c6d9428897dc672185872d30d17James Dong // 3142dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 3152dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 3162dec2b5be2056c6d9428897dc672185872d30d17James Dong 31778a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 3182dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 31978a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 3 3202dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 3212dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 3222dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 3232dec2b5be2056c6d9428897dc672185872d30d17James Dong 3242dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 3252dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 3262dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 32778a1a286f736888ae7af8860b2c424af0d978848James Dong static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 3282dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 3292dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 3302dec2b5be2056c6d9428897dc672185872d30d17James Dong 33178a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file size limit is set 332a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 33378a1a286f736888ae7af8860b2c424af0d978848James Dong size = mMaxFileSizeLimitBytes * 6 / 1000; 33478a1a286f736888ae7af8860b2c424af0d978848James Dong } 33578a1a286f736888ae7af8860b2c424af0d978848James Dong 33678a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file duration limit is set 33778a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileDurationLimitUs != 0) { 33878a1a286f736888ae7af8860b2c424af0d978848James Dong if (bitRate > 0) { 33978a1a286f736888ae7af8860b2c424af0d978848James Dong int64_t size2 = 34078a1a286f736888ae7af8860b2c424af0d978848James Dong ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 34178a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 34278a1a286f736888ae7af8860b2c424af0d978848James Dong // When both file size and duration limits are set, 34378a1a286f736888ae7af8860b2c424af0d978848James Dong // we use the smaller limit of the two. 34478a1a286f736888ae7af8860b2c424af0d978848James Dong if (size > size2) { 34578a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 34678a1a286f736888ae7af8860b2c424af0d978848James Dong } 34778a1a286f736888ae7af8860b2c424af0d978848James Dong } else { 34878a1a286f736888ae7af8860b2c424af0d978848James Dong // Only max file duration limit is set 34978a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 35078a1a286f736888ae7af8860b2c424af0d978848James Dong } 3512dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3522dec2b5be2056c6d9428897dc672185872d30d17James Dong } 35378a1a286f736888ae7af8860b2c424af0d978848James Dong 3542dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 3552dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 3562dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3572dec2b5be2056c6d9428897dc672185872d30d17James Dong 3582dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 3592dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 3602dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 3612dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 3622dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3632dec2b5be2056c6d9428897dc672185872d30d17James Dong 364a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 3652dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 3662dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 3672dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 3682dec2b5be2056c6d9428897dc672185872d30d17James Dong} 3692dec2b5be2056c6d9428897dc672185872d30d17James Dong 3702dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 37120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 37225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 37320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 37420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 375a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong /* 376a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * Check mMaxFileSizeLimitBytes at the beginning 377a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * since mMaxFileSizeLimitBytes may be implicitly 378a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * changed later for 32-bit file offset even if 379a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * user does not ask to set it explicitly. 380a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong */ 381a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0) { 382a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested = true; 383a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong } 384a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong 3852dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 3862dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 3872dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 3882dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 3892dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 3902dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3912dec2b5be2056c6d9428897dc672185872d30d17James Dong 3921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mUse32BitOffset) { 3931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // Implicit 32 bit file size limit 3941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes == 0) { 3951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 3961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 3971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 3981f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // If file size is set to be larger than the 32 bit file 3991f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // size limit, treat it as an error. 4001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 401872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGW("32-bit file size limit (%lld bytes) too big. " 402d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong "It is changed to %lld bytes", 403d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes, kMax32BitFileSize); 404d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 408b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong int32_t use2ByteNalLength; 409b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (param && 410b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 411b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong use2ByteNalLength) { 412b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength = false; 4132dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4142dec2b5be2056c6d9428897dc672185872d30d17James Dong 415065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 41693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 417a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 418a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 419a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 42093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 421a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 422a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 423a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 424a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 4258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 4268f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 4278f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 4288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 4298f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 4308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 4318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 4327837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 4337837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 4347837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 4357837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4367837c17063a4c50bc856ba59418516fdab731de7James Dong 43720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 43893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 43993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int32_t fileType; 44093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (param && param->findInt32(kKeyFileType, &fileType) && 44193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong fileType != OUTPUT_FORMAT_MPEG_4) { 44293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 44393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } else { 44493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("isom"); 44593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 44693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 44720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 44820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 44993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 45020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 45120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4527837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 45320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4547837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 4552dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 4562dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 4572dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 4582dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4592dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 4607837c17063a4c50bc856ba59418516fdab731de7James Dong } 4617837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 4627837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 4637837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 4647837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 4657837c17063a4c50bc856ba59418516fdab731de7James Dong 4667837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 4677837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 4687837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 4691acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 4701acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 4711acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 4721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 4731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 4741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 4761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 4771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 4781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 4791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 481a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 482a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 48320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 4841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 485a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 48625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 48720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 48820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const { 4901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong return mUse32BitOffset; 4911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 4921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 49337187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 494a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mFile == NULL) { 49537187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 496a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 497a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 49837187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 499a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 500a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 50137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 50237187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 50337187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 50437187916a486504acaf83bea30147eb5fbf46ae5James Dong } 505a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 50637187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 507a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 508a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 5091c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 5101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("stopWriterThread"); 5111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 5131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 5141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 5161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 5171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 5181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 5201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 5211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 5221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 523aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong/* 524aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * MP4 file standard defines a composition matrix: 525aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * | a b u | 526aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * | c d v | 527aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * | x y w | 528aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * 529aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * the element in the matrix is stored in the following 530aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * order: {a, b, u, c, d, v, x, y, w}, 531aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * where a, b, c, d, x, and y is in 16.16 format, while 532aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong * u, v and w is in 2.30 format. 533aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong */ 534aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) { 535aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong LOGV("writeCompositionMatrix"); 536aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong uint32_t a = 0x00010000; 537aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong uint32_t b = 0; 538aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong uint32_t c = 0; 539aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong uint32_t d = 0x00010000; 540aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong switch (degrees) { 541aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong case 0: 542aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong break; 543aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong case 90: 544aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong a = 0; 545aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong b = 0x00010000; 546aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong c = 0xFFFF0000; 547aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong d = 0; 548aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong break; 549aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong case 180: 550aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong a = 0xFFFF0000; 551aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong d = 0xFFFF0000; 552aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong break; 553aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong case 270: 554aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong a = 0; 555aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong b = 0xFFFF0000; 556aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong c = 0x00010000; 557aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong d = 0; 558aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong break; 559aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong default: 560aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong CHECK(!"Should never reach this unknown rotation"); 561aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong break; 562aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong } 563aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong 564aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(a); // a 565aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(b); // b 566aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(0); // u 567aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(c); // c 568aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(d); // d 569aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(0); // v 570aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(0); // x 571aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(0); // y 572aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeInt32(0x40000000); // w 573aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong} 574aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong 57537187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() { 57620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 57737187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 57820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 57920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 58037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 5818f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 58220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 58320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 58437187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 58537187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 58637187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 58737187916a486504acaf83bea30147eb5fbf46ae5James Dong } 58820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5898f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 5908f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 5918f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 59220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 59320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 59420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 5967837c17063a4c50bc856ba59418516fdab731de7James Dong 59737187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 59837187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 59937187916a486504acaf83bea30147eb5fbf46ae5James Dong fflush(mFile); 60037187916a486504acaf83bea30147eb5fbf46ae5James Dong fclose(mFile); 60137187916a486504acaf83bea30147eb5fbf46ae5James Dong mFile = NULL; 60237187916a486504acaf83bea30147eb5fbf46ae5James Dong mStarted = false; 60337187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 60437187916a486504acaf83bea30147eb5fbf46ae5James Dong } 60537187916a486504acaf83bea30147eb5fbf46ae5James Dong 60620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 6071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 6081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 6091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 6101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 4, mFile); 6111acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 6121acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset + 8, SEEK_SET); 6131acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 6141acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 6151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 8, mFile); 6161acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 6177837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 61820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 61920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 6207837c17063a4c50bc856ba59418516fdab731de7James Dong const off_t moovOffset = mOffset; 6217837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 6227837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 6237837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6247837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 625c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6; 62620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 62720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 62820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 62920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 63020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 63120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 63220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 6338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong writeInt32(mTimeScale); // mvhd timescale 6341acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(duration); 6351acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(0x10000); // rate: 1.0 63620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 63720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 63820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 63920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 640aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong writeCompositionMatrix(0); 64120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 64220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 64720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 64820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 65120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 65220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 6531acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong (*it)->writeTrackHeader(id, mUse32BitOffset); 65420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 65520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 65620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6577837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6587837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 6597837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 6607837c17063a4c50bc856ba59418516fdab731de7James Dong 6617837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 6627837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 6637837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 6647837c17063a4c50bc856ba59418516fdab731de7James Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); 6657837c17063a4c50bc856ba59418516fdab731de7James Dong 6667837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 6672dec2b5be2056c6d9428897dc672185872d30d17James Dong fseeko(mFile, mOffset, SEEK_SET); 6687837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 6697837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 6707837c17063a4c50bc856ba59418516fdab731de7James Dong 6717837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 6727837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 6737837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6747837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6752dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 6762dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 6777837c17063a4c50bc856ba59418516fdab731de7James Dong } 6787837c17063a4c50bc856ba59418516fdab731de7James Dong 6790c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 68020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6817837c17063a4c50bc856ba59418516fdab731de7James Dong fflush(mFile); 68220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fclose(mFile); 68320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mFile = NULL; 684a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 68537187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 68620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 68720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 68813aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 68913aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 69013aec890216948b0c364f8f92792129d0335f506James Dong return OK; 69113aec890216948b0c364f8f92792129d0335f506James Dong} 69213aec890216948b0c364f8f92792129d0335f506James Dong 69313aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 69413aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 69513aec890216948b0c364f8f92792129d0335f506James Dong} 69613aec890216948b0c364f8f92792129d0335f506James Dong 69713aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 69813aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 69913aec890216948b0c364f8f92792129d0335f506James Dong} 70020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 70113aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 70220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t old_offset = mOffset; 70320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 70420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 70520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1, buffer->range_length(), mFile); 70620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 70920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 71020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 71120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 71303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 71403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 71503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 71603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 71703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 71803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 71903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 72003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 72103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 72203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 72303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 72403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 72503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 72613aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 72730ab66297501757d745b9ae10da61adcd891f497Andreas Huber off_t old_offset = mOffset; 72830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 72930ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 73003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 731b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mUse4ByteNalLength) { 732b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 24; 733b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite(&x, 1, 1, mFile); 734b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 16) & 0xff; 735b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite(&x, 1, 1, mFile); 736b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 8) & 0xff; 737b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite(&x, 1, 1, mFile); 738b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 739b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite(&x, 1, 1, mFile); 740b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 741b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 742b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 1, length, mFile); 743b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 4; 744b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 745b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong CHECK(length < 65536); 74630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 747b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 8; 748b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite(&x, 1, 1, mFile); 749b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 750b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite(&x, 1, 1, mFile); 751b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 752b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 1, length, mFile); 753b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 2; 754b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 75530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 75630ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 75730ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 75830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 7597837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 7607837c17063a4c50bc856ba59418516fdab731de7James Dong const void *ptr, size_t size, size_t nmemb, FILE *stream) { 7617837c17063a4c50bc856ba59418516fdab731de7James Dong 7627837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 7637837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 7641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 7651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 7667837c17063a4c50bc856ba59418516fdab731de7James Dong for (List<off_t>::iterator it = mBoxes.begin(); 7677837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 7687837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 7697837c17063a4c50bc856ba59418516fdab731de7James Dong } 7707837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 7717837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream); 7727837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 7737837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 7747837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 7757837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 7767837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 7777837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 7787837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 7797837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 7807837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 7817837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 7827837c17063a4c50bc856ba59418516fdab731de7James Dong } 7837837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 7847837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 7857837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 7867837c17063a4c50bc856ba59418516fdab731de7James Dong } 7877837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 7887837c17063a4c50bc856ba59418516fdab731de7James Dong} 7897837c17063a4c50bc856ba59418516fdab731de7James Dong 79020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 7910c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 79220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7937837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 7947837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 79520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 79620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 79720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 79820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 79920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 80020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 8010c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 80220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 80320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t offset = *--mBoxes.end(); 80420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 80520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8067837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 8077837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 8087837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 8097837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 8107837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, offset, SEEK_SET); 8117837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 8127837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 8137837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 8147837c17063a4c50bc856ba59418516fdab731de7James Dong } 81520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 81620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 81720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 8187837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 1, mFile); 81920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 82020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 82220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 8237837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 2, mFile); 82420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 82520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 82720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 8287837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 4, mFile); 82920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 83020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 83220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 8337837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 8, mFile); 83420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 83720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 8387837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, n + 1, mFile); 83920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 84020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 8420c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 8437837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, 4, mFile); 84420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 84520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 8477837c17063a4c50bc856ba59418516fdab731de7James Dong write(data, 1, size, mFile); 84820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 84920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85078a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const { 85178a1a286f736888ae7af8860b2c424af0d978848James Dong return mStreamableFile; 85278a1a286f736888ae7af8860b2c424af0d978848James Dong} 85378a1a286f736888ae7af8860b2c424af0d978848James Dong 854d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 855d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 856d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 857d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 858d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 859d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 860956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 861d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 862d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 863d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 864d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 8651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 866acd234bba9f048971d66890009eeff9a8db94be3James Dong // Be conservative in the estimate: do not exceed 95% of 867acd234bba9f048971d66890009eeff9a8db94be3James Dong // the target file limit. For small target file size limit, though, 868acd234bba9f048971d66890009eeff9a8db94be3James Dong // this will not help. 869acd234bba9f048971d66890009eeff9a8db94be3James Dong return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 870d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 871d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 872d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 873d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 874d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 875d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 876d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 877d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 878d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 879d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 880d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 881d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 882d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 883d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 884d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 885d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 886d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 88725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 88825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 88925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 89025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 89125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 89225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 89325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 89425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 89525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 89625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 89725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 89825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 89925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 900f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 901f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 902f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 9033c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 904065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 905f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 906f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 9073c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 9083c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 9093c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 910f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 9113c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 9123c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 9133c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 9143c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 91558ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 91658ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 91758ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 91858ae9c530247668f8af36e30d228c716c226b3d4James Dong} 91958ae9c530247668f8af36e30d228c716c226b3d4James Dong 92020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 92120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 92325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber MPEG4Writer *owner, const sp<MediaSource> &source) 92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 92525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 928a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 929a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 930c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 931956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 932be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 93320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 93425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 935548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 936aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong mReachedEOS(false), 937aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong mRotation(0) { 93819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 9398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 9401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 9411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 9421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 9431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 9441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 9451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 9461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 947c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 948c059860c73678a202bfa33062723e8f82fb779d9James Dong} 949c059860c73678a202bfa33062723e8f82fb779d9James Dong 9501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() { 9511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset() 9531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ? mNumStcoTableEntries * 4 9541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong : mNumStcoTableEntries * 8; 9551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4); 9571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 95878a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 95978a1a286f736888ae7af8860b2c424af0d978848James Dong if (!mOwner->isFileStreamable()) { 96078a1a286f736888ae7af8860b2c424af0d978848James Dong // Reserved free space is not large enough to hold 96178a1a286f736888ae7af8860b2c424af0d978848James Dong // all meta data and thus wasted. 96278a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 + // stsc box size 96378a1a286f736888ae7af8860b2c424af0d978848James Dong mNumStssTableEntries * 4 + // stss box size 96478a1a286f736888ae7af8860b2c424af0d978848James Dong mNumSttsTableEntries * 8 + // stts box size 96578a1a286f736888ae7af8860b2c424af0d978848James Dong stcoBoxSizeBytes + // stco box size 96678a1a286f736888ae7af8860b2c424af0d978848James Dong stszBoxSizeBytes; // stsz box size 96778a1a286f736888ae7af8860b2c424af0d978848James Dong } 9681f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9691f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry( 9711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t chunkId, size_t sampleId) { 9721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong StscTableEntry stscEntry(chunkId, sampleId, 1); 9741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStscTableEntries.push_back(stscEntry); 9751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStscTableEntries; 9761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 9791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStssTableEntries.push_back(sampleId); 9801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStssTableEntries; 9811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry( 9841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t sampleCount, int64_t durationUs) { 9851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong SttsTableEntry sttsEntry(sampleCount, durationUs); 9871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mSttsTableEntries.push_back(sttsEntry); 9881f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumSttsTableEntries; 9891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addChunkOffset(off_t offset) { 9921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStcoTableEntries; 9931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mChunkOffsets.push_back(offset); 9941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 996c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 997c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 998c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 999c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 1000c059860c73678a202bfa33062723e8f82fb779d9James Dong 1001c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 1002c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 1003c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 1004c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1005c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 1006c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 1007c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1008c059860c73678a202bfa33062723e8f82fb779d9James Dong 1009c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 1010c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 1011c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1012c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 1013c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1014c059860c73678a202bfa33062723e8f82fb779d9James Dong 10158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 101619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 101719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 101819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 101919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 102019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 102119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 102219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 102319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 102419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 102519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 102619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 102719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 102819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 102919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 103019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 103119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 103219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 103319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 103419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 103519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 103619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 103719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 103819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 103919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 104019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 104119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 104219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 104319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 104419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 104519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 104619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 104720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 104820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104920111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 105020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 105120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 105220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 105320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 105420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 105520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 105620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 105720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 105893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 105993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 106093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 106193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 106293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 106393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 106493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 106593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 106693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 106793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 106893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 106993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 107093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 107193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 107293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 10731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 10741c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 10751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 10761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 10771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 10781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 10791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 10801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10811c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 10821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 10831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 10841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 10851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 10871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 10881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 10901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 10911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 10921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 10931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 10971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 10981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10991c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeFirstChunk(ChunkInfo* info) { 11001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeFirstChunk: %p", info->mTrack); 11011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = info->mChunks.begin(); 11031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 11041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != chunkIt->mSamples.end(); ++it) { 11051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = info->mTrack->isAvc() 11071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ? addLengthPrefixedSample_l(*it) 11081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong : addSample_l(*it); 11091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it == chunkIt->mSamples.begin()) { 11101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mTrack->addChunkOffset(offset); 11111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Done with the current chunk. 11151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Release all the samples in this chunk. 11161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!chunkIt->mSamples.empty()) { 11171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 11181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 11191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 11201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.erase(it); 11211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.clear(); 11231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mChunks.erase(chunkIt); 11241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11261c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeChunks() { 11271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeChunks"); 11281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 11291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mChunkInfos.empty()) { 11301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!it->mChunks.empty()) { 11321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(OK, writeOneChunk()); 11331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ++outstandingChunks; 11341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mTrack = NULL; 11361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.erase(it); 11371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 11391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 11401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11421c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::writeOneChunk() { 11431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeOneChunk"); 11441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Find the smallest timestamp, and write that chunk out 11461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // XXX: What if some track is just too slow? 11471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 11481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 11491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 11511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 11521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 11531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 11541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 11551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 11561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 11611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 11621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 11631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 11661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 11671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 11701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 11711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeFirstChunk(&(*it)); 11721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 11751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11771c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 11781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 11791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1180a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 11811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 11821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 11831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 11841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 11851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(writeOneChunk(), OK); 11861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 11901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Write ALL samples 11911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 11921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeChunks(); 11931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11961c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 11971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 11981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 12001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1201e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 12021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 12031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 12041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 12051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 12061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 12071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 12101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 12111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 12121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 12131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 12141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 12151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 121893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1219a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1220a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1221a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1222a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1223a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 122425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 122593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 122619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 122719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 122819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 122919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 1230aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong int32_t rotationDegrees; 1231aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong if (!mIsAudio && params && params->findInt32(kKeyRotationDegree, &rotationDegrees)) { 1232aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong mRotation = rotationDegrees; 1233aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong } 1234aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong 12355b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong mIsRealTimeRecording = true; 1236e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1237e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1238e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1239e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1240e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1241e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1242e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 124393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 124493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1245f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1246f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1247f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 124825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 124925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 125025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 125125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 125220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 125320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 125420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 125520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 125620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 125720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1258c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 125925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1260956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 12611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStcoTableEntries = 0; 12621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStssTableEntries = 0; 12631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStscTableEntries = 0; 12641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumSttsTableEntries = 0; 12651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes = 0; 1266872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = false; 1267872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = 0; 1268872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 0; 1269872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = 0; 1270872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 0; 1271872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = 0; 127220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 127325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 127420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 127525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 127625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 127720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 127820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 127937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1280a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 128137187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1282a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1283a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 128437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 128520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 128637187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 128720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 128820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 128920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 129020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 129120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 129220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 129320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 129437187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = (status_t) dummy; 129537187916a486504acaf83bea30147eb5fbf46ae5James Dong 129637187916a486504acaf83bea30147eb5fbf46ae5James Dong { 129737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = mSource->stop(); 129837187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { 129937187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 130037187916a486504acaf83bea30147eb5fbf46ae5James Dong } 130137187916a486504acaf83bea30147eb5fbf46ae5James Dong } 130237187916a486504acaf83bea30147eb5fbf46ae5James Dong 130337187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 130420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 130520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 130625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 130725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 130825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 130925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 131020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 131120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 131220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 131320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 131437187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 131537187916a486504acaf83bea30147eb5fbf46ae5James Dong return (void *) err; 131620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 131720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 13183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 13193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 13203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 13223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 13233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 13263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 13273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 13293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 13313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 13323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 13333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 13343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 13363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 13373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 13393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 13423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 13433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 13453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 13463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 13473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 13493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 13503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 13513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 13523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 13533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 13563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 13573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 13583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 13593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 13603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 13623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 13633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 13643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 13653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 13663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 13673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 13683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 13693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 13703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 13713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 13743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 13753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 13763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 13783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 13813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 13823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 13833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 13853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 13863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 13873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 13883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 13893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 13923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 13933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 13943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 13953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 13983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 13993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 14013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 14023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 14033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 14043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 14053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 14063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 14073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 14083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 14093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 14103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 14113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 14123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 14133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 14143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 14153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 14163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 14173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 14203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 14213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 14233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 14243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 14253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 14263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 14293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 14303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 14323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 14333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 14343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 14383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 14423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 14433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 14443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 14453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 14483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 14493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 14503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 14513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 14523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 14563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 14573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 14623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 14633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 14643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 14653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 14663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 14693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 14703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 14753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 14763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 14773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 14783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 14793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 14803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 14813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 14853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1486548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 148703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 148803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1489548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 149003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1491548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 149203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 149303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 149403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 14953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 14963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 149703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 149803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 149903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 15013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 15023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 150303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 150403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 150603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 150703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 150803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 15103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 151103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 151203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 15133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 15143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 15153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 15163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 151703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 1519b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1520b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 3; // length size == 4 bytes 1521b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1522b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 1; // length size == 2 bytes 1523b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 152403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 15263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 15273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 15283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 15293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 15303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 15313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 15323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 15333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 15343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 15353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 15373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 15383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 15393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 15423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 15433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 15443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 15453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 15463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 15533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 15543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 15553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 155603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 155703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 155803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 155903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1560872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1561872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications 1562872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows: 1563872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1564872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of 1565872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs 1566872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of 1567872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small 1568872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value 1569872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding 1570872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep 1571872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the 1572872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is 1573872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track. 1574872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1575872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found 1576872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed 1577872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames 1578872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames 1579872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period. 1580872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion 1581872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames 1582872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is 1583872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media 1584872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a 1585872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5). 1586872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1587872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that 1588872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift. 1589872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time 1590872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold 1591872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs. 1592872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental 1593872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the 1594872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift. 1595872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio 1596872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of 1597872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold 1598872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of 1599872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio 1600872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time 1601872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no 1602872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time 1603872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some 1604872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want 1605872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being. 1606872a481558350634a3fd5cb67939de288af00ecbJames Dong*/ 1607872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) { 1608872a481558350634a3fd5cb67939de288af00ecbJames Dong if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >= 1609872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs) { 1610872a481558350634a3fd5cb67939de288af00ecbJames Dong 1611872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("New media time adjustment period at %lld us", *timestampUs); 1612872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = true; 1613872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 1614872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample) >> 1; 1615872a481558350634a3fd5cb67939de288af00ecbJames Dong 1616872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = *timestampUs; 1617872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = mNumSamples; 1618872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs(); 1619872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 1620872a481558350634a3fd5cb67939de288af00ecbJames Dong totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs; 1621872a481558350634a3fd5cb67939de288af00ecbJames Dong 1622872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs; 1623872a481558350634a3fd5cb67939de288af00ecbJames Dong 1624872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on incremental adjusted time per frame 1625872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t adjustTimePerFrameUs = 1626872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames; 1627872a481558350634a3fd5cb67939de288af00ecbJames Dong 1628872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs < 0) { 1629872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs = -adjustTimePerFrameUs; 1630872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1631872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs >= 5000) { 1632872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Adjusted time per video frame is %lld us", 1633872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs); 1634872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"Video frame time adjustment is too large!"); 1635872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1636872a481558350634a3fd5cb67939de288af00ecbJames Dong 1637872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on total accumulated time drift within a period of 1638872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 1639872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000) 1640872a481558350634a3fd5cb67939de288af00ecbJames Dong / kVideoMediaTimeAdjustPeriodTimeUs; 1641872a481558350634a3fd5cb67939de288af00ecbJames Dong 1642872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage < 0) { 1643872a481558350634a3fd5cb67939de288af00ecbJames Dong driftPercentage = -driftPercentage; 1644872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1645872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage > 5) { 1646872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Audio track has time drift %lld us over %lld us", 1647872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs, 1648872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs); 1649872a481558350634a3fd5cb67939de288af00ecbJames Dong 1650872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"The audio track media time drifts too much!"); 1651872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1652872a481558350634a3fd5cb67939de288af00ecbJames Dong 1653872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1654872a481558350634a3fd5cb67939de288af00ecbJames Dong 1655872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsMediaTimeAdjustmentOn) { 1656872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mNumSamples - mPrevMediaTimeAdjustSample <= 1657872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames) { 1658872a481558350634a3fd5cb67939de288af00ecbJames Dong 1659872a481558350634a3fd5cb67939de288af00ecbJames Dong // Do media time incremental adjustment 1660872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t incrementalAdjustTimeUs = 1661872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs * 1662872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample)) 1663872a481558350634a3fd5cb67939de288af00ecbJames Dong / mMediaTimeAdjustNumFrames; 1664872a481558350634a3fd5cb67939de288af00ecbJames Dong 1665872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1666872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs); 1667872a481558350634a3fd5cb67939de288af00ecbJames Dong 1668872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Incremental video frame media time adjustment: %lld us", 1669872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs)); 1670872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1671872a481558350634a3fd5cb67939de288af00ecbJames Dong // Within the remaining adjustment period, 1672872a481558350634a3fd5cb67939de288af00ecbJames Dong // no incremental adjustment is needed. 1673872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1674872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs); 1675872a481558350634a3fd5cb67939de288af00ecbJames Dong 1676872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Fixed video frame media time adjustment: %lld us", 1677872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs)); 1678872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1679872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1680872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1681872a481558350634a3fd5cb67939de288af00ecbJames Dong 1682872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1683872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that 1684872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information 1685872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio 1686872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger 1687872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 1688872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined. 1689872a481558350634a3fd5cb67939de288af00ecbJames Dong */ 1690872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 1691872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftTimeUs = 0; 1692872a481558350634a3fd5cb67939de288af00ecbJames Dong if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 1693872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 1694872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 1695872a481558350634a3fd5cb67939de288af00ecbJames Dong mOwner->setDriftTimeUs(timeUs); 1696872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1697872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1698872a481558350634a3fd5cb67939de288af00ecbJames Dong 169937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 170030ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 170113aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 170213aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 170313aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 170413aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 17058f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 17068f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1707c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1708c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 17098f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1710be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1711a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 17121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1713e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1714a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong if (mIsAudio) { 1715a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 1716a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } else { 1717a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 1718a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } 1719d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 172020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1721ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 172293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 172320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 172493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 172520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 172620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 172720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 172813aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 172920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 173020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 173120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1732a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1733a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1734a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1735a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1736a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1737a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1738a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1739a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1740a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 174130ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 174230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 174303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 174403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 174503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1746548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1747548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 17481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 174903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 175003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 175103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 175203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1753be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 17541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 175503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 175603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 175703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 175803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 175903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 176003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 176130ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 176230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 176330ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 176430ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 176530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1766548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 176730ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 1768a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1769a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1770d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 1771d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 1772d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1773d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1774d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 1775d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 1776d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 1777d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 1778d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 1779d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 17801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 1781e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 1782b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong size_t sampleSize = copy->range_length(); 1783b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mIsAvc) { 1784b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1785b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 4; 1786b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1787b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 2; 1788b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1789b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1790050b28a593350047845a45a14cc5026221ac1620James Dong 1791d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 17921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes += sampleSize; 17931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong updateTrackSizeEstimate(); 17941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1795d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 1796d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1797d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1798d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1799d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 1800d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1801d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1802d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1803d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1804050b28a593350047845a45a14cc5026221ac1620James Dong 1805d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 1806d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1807d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 18088428af5381e835cc783b7ecb0d71cb60961c99c2James Dong /* 18098428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The original timestamp found in the data buffer will be modified as below: 18108428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18118428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * There is a playback offset into this track if the track's start time 18128428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is not the same as the movie start time, which will be recorded in edst 18138428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * box of the output file. The playback offset is to make sure that the 18148428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * starting time of the audio/video tracks are synchronized. Although the 18158428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * track's media timestamp may be subject to various modifications 18168428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * as outlined below, the track's playback offset time remains unchanged 18178428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * once the first data buffer of the track is received. 18188428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18198428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The media time stamp will be calculated by subtracting the playback offset 18208428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * (and potential pause durations) from the original timestamp in the buffer. 18218428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18228428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If this track is a video track for a real-time recording application with 18238428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * both audio and video tracks, its media timestamp will subject to further 18248428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * modification based on the media clock of the audio track. This modification 18258428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is needed for the purpose of maintaining good audio/video synchronization. 18268428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18278428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If the recording session is paused and resumed multiple times, the track 18288428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * media timestamp will be modified as if the recording session had never been 18298428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * paused at all during playback of the recorded output file. In other words, 18308428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * the output file will have no memory of pause/resume durations. 18318428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18328428af5381e835cc783b7ecb0d71cb60961c99c2James Dong */ 1833d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 18348428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs); 1835d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1836d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 18378644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 1838f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 1839f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 18408428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs = mStartTimestampUs; 18413c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 184248c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 1843a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 18448428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 18458428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(durExcludingEarlierPausesUs >= 0); 18468428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 18478428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(pausedDurationUs >= lastDurationUs); 18488428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs += pausedDurationUs - lastDurationUs; 1849a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 1850a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1851a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1852a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 18538428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(timestampUs >= 0); 1854872a481558350634a3fd5cb67939de288af00ecbJames Dong 1855872a481558350634a3fd5cb67939de288af00ecbJames Dong // Media time adjustment for real-time applications 1856872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsRealTimeRecording) { 1857872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 1858872a481558350634a3fd5cb67939de288af00ecbJames Dong updateDriftTime(meta_data); 1859872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1860872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustMediaTime(×tampUs); 1861e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1862e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1863872a481558350634a3fd5cb67939de288af00ecbJames Dong 1864e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 1865e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1866e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 18674f86a980fee1880dca61b828599fa6d76755a485James Dong LOGW("Frame arrives too late!"); 18684f86a980fee1880dca61b828599fa6d76755a485James Dong // Don't drop the late frame, since dropping a frame may cause 18694f86a980fee1880dca61b828599fa6d76755a485James Dong // problems later during playback 18704f86a980fee1880dca61b828599fa6d76755a485James Dong 18714f86a980fee1880dca61b828599fa6d76755a485James Dong // The idea here is to avoid having two or more samples with the 18724f86a980fee1880dca61b828599fa6d76755a485James Dong // same timestamp in the output file. 18734f86a980fee1880dca61b828599fa6d76755a485James Dong if (mTimeScale >= 1000000LL) { 187440e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + 1; 18754f86a980fee1880dca61b828599fa6d76755a485James Dong } else { 187640e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale; 18774f86a980fee1880dca61b828599fa6d76755a485James Dong } 1878e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1879e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1880e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 18818428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s media time stamp: %lld and previous paused duration %lld", 18828428af5381e835cc783b7ecb0d71cb60961c99c2James Dong mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); 1883c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 1884c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 18853b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 18863b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 18878644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 1888ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 1889ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 1890c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 1891c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 1892c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 1893c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 1894c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 1895c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 1896c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 1897c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 1898c059860c73678a202bfa33062723e8f82fb779d9James Dong 1899c059860c73678a202bfa33062723e8f82fb779d9James Dong if (currDurationTicks != lastDurationTicks) { 19001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 1901be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 1902be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1903be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 1904be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1905be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1906be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1907ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 1908be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 1909be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 19108644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 1911be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 19128644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 1913c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 19148644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 191520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1916d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 19171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStssTableEntry(mNumSamples); 1918d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 1919d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 192093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 192193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 192293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 192393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 1924faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 192593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 192658ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 19271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 192858ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 192958ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 19301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addChunkOffset(offset); 193158ae9c530247668f8af36e30d228c716c226b3d4James Dong } 193258ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 193358ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 193458ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 193558ae9c530247668f8af36e30d228c716c226b3d4James Dong } 193613aec890216948b0c364f8f92792129d0335f506James Dong 193713aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 193813aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 19391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, 1); 19401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 194113aec890216948b0c364f8f92792129d0335f506James Dong } else { 194213aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 194313aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 194413aec890216948b0c364f8f92792129d0335f506James Dong } else { 194513aec890216948b0c364f8f92792129d0335f506James Dong if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 194613aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 194713aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 194813aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 194913aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 19501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(nChunks, mChunkSamples.size()); 195113aec890216948b0c364f8f92792129d0335f506James Dong } 19521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 195313aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 195413aec890216948b0c364f8f92792129d0335f506James Dong } 195513aec890216948b0c364f8f92792129d0335f506James Dong } 195613aec890216948b0c364f8f92792129d0335f506James Dong } 195713aec890216948b0c364f8f92792129d0335f506James Dong 195820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 195925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 1960a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong if (mSampleSizes.empty() || // no samples written 1961a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (!mIsAudio && mNumStssTableEntries == 0) || // no sync frames for video 1962a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (OK != checkCodecSpecificData())) { // no codec specific data 1963690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 1964f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 1965faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, -1, err); 1966be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 196713aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 196858ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 19691f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(1, mNumSamples); 197058ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 19711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, mChunkSamples.size()); 19721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 197313aec890216948b0c364f8f92792129d0335f506James Dong } 197413aec890216948b0c364f8f92792129d0335f506James Dong 1975be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 1976be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 1977be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 1978ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 19798f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 1980be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1981be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 1982be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 19831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 1984c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 198525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 19861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 19871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video"); 1988872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 1989872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); 1990872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1991365a963142093a1cd8efdcea76b5f65096a5b115James Dong 199237187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 199337187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 199437187916a486504acaf83bea30147eb5fbf46ae5James Dong } 199537187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 1996365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1997365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1998faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 1999faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 2000215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 2001215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 200293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 2003faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err); 200493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 200593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 200693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 200793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 2008faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 2009faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong const MPEG4Writer::Track* track, int64_t timeUs, status_t err) { 2010faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 2011faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t nTracks = mTracks.size(); 2012faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks >= 1); 2013faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks < 64); // Arbitrary number 2014faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2015faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t trackNum = 0; 2016faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(trackNum < nTracks); 2017faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum <<= 16; 2018faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2019faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 2020faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 2021faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 2022faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_ERROR, 2023faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_ERROR_UNKNOWN, 2024faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2025faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2026faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2027faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2028faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 2029faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 2030faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 2031faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS, 2032faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2033faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2034faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 2035faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 2036faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 2037faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, 2038faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 2039faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2040faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 2041faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2042d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2043d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong LOGV("setDriftTimeUs: %lld us", driftTimeUs); 2044e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2045d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 2046e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2047e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2048e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 2049e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 2050e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2051e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 2052e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2053e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2054b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() { 2055b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong return mUse4ByteNalLength; 2056b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong} 2057b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 20581c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 20591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 20601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 20611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 20621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 206313aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 206420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 206520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 20663b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 2067c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 206820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 206920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2070d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2071d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 2072d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 2073d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2074690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 2075690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 2076690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2077690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2078690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2079690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2080690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 2081690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 2082a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Missing codec specific data"); 2083690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2084690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2085690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 2086690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 2087690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 2088a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Unexepected codec specific data found"); 2089690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2090690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2091690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2092690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 2093690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 2094690f546b0ee548dbfe997df36418e5302ec2d786James Dong 20951acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader( 20961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t trackID, bool use32BitOffset) { 209720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 209820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 20990c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 210020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21018f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 21021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 21038f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 210420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 21058f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 21068f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 210720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 210820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 210920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 211020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 21111acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Flags = 7 to indicate that the track is enabled, and 21121acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // part of the presentation 21131acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x07); // version=0, flags=7 211420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 211520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 211620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 211720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 21188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t tkhdDuration = 21198f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 21208f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 212120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 212220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 212320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 212420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 21251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 212620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 212720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2128aca1fe35480ae76dd6bae167ade40adc955e2d0dJames Dong mOwner->writeCompositionMatrix(mRotation); 212920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 213120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 213220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 213320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 213420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 213520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 213620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 21370c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 213820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2139050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2140050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 214120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 214220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 214320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2144f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 2145f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong if (mStartTimestampUs != moovStartTimeUs) { 21463c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("edts"); 21473c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("elst"); 21481acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 21491acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(2); // never ends with an empty list 21508f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 21518f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // First elst entry: specify the starting time offset 21528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; 21538428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("OffsetUs: %lld", offsetUs); 21548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; 21558f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timecale 21568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(-1); // starting time offset 21578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(1 << 16); // rate = 1.0 21588f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 21598f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // Second elst entry: specify the track duration 21608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 21618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timescale 21621acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); 21631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); 21643c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 21653c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 21663c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 21673c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 216820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 216920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 217020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 217120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 217220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 217320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 21748f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mTimeScale); // media timescale 21758f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 21768f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mdhdDuration); // use media timescale 21771acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Language follows the three letter standard ISO-639-2/T 21781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // 'e', 'n', 'g' for "English", for instance. 21791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Each character is packed as the difference between its ASCII value and 0x60. 21801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // For "English", these are 00101, 01110, 00111. 21811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // XXX: Where is the padding bit located: 0x15C7? 21821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(0); // language code 218320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 218420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 218520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 218620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 218720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2188050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // component type: should be mhlr 21891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 219020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 219120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 219220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 21931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Removing "r" for the name string just makes the string 4 byte aligned 21941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 219520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 219620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 219720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 21981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 219920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 220020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 220120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 220220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 220320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 220420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 220520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 22061acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x01); // version=0, flags=1 220720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 220820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 220920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 221020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 221120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 221220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 2213050b28a593350047845a45a14cc5026221ac1620James Dong 2214050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dinf"); 2215050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dref"); 2216050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 22171acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // entry count (either url or urn) 22181acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // The table index here refers to the sample description index 22191acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // in the sample table entries. 2220050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("url "); 22211acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2222050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // url 2223050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dref 2224050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dinf 2225050b28a593350047845a45a14cc5026221ac1620James Dong 222620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 222720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 222820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 222920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 223020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 22311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 223225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 223318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 223425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 223518291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 223625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 2237050b28a593350047845a45a14cc5026221ac1620James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2238050b28a593350047845a45a14cc5026221ac1620James Dong fourcc = "mp4a"; 223925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 224025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 224125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 224225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 224325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 224425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 224520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 224620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 2247050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x1); // data ref index 224820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 224920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 2250050b28a593350047845a45a14cc5026221ac1620James Dong int32_t nChannels; 2251050b28a593350047845a45a14cc5026221ac1620James Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2252050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(nChannels); // channel count 225320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 225420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 225520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 225620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 225720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 225820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 22590c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 226020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 2261050b28a593350047845a45a14cc5026221ac1620James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2262050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("esds"); 226351dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 226451dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 2265050b28a593350047845a45a14cc5026221ac1620James Dong 2266050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2267050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x03); // ES_DescrTag 2268050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2269050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x0000);// ES_ID 2270050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); 2271050b28a593350047845a45a14cc5026221ac1620James Dong 2272050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2273050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2274050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2275050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x15); // streamType AudioStream 2276050b28a593350047845a45a14cc5026221ac1620James Dong 2277050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x03); // XXX 2278050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2279050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // max bit rate 2280050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // avg bit rate 2281050b28a593350047845a45a14cc5026221ac1620James Dong 2282050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2283050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(mCodecSpecificDataSize); 2284050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2285050b28a593350047845a45a14cc5026221ac1620James Dong 2286050b28a593350047845a45a14cc5026221ac1620James Dong static const uint8_t kData2[] = { 2287050b28a593350047845a45a14cc5026221ac1620James Dong 0x06, // SLConfigDescriptorTag 2288050b28a593350047845a45a14cc5026221ac1620James Dong 0x01, 2289050b28a593350047845a45a14cc5026221ac1620James Dong 0x02 2290050b28a593350047845a45a14cc5026221ac1620James Dong }; 2291050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(kData2, sizeof(kData2)); 2292050b28a593350047845a45a14cc5026221ac1620James Dong 2293050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // esds 22945aff464f67322cd13dc8ed165806971cfff2e4d5James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 22955aff464f67322cd13dc8ed165806971cfff2e4d5James Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 22965aff464f67322cd13dc8ed165806971cfff2e4d5James Dong // 3gpp2 Spec AMRSampleEntry fields 22975aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->beginBox("damr"); 22985aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeCString(" "); // vendor: 4 bytes 22995aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // decoder version 23005aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 23015aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // mode change period 23025aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(1); // frames per sample 23035aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->endBox(); 2304050b28a593350047845a45a14cc5026221ac1620James Dong } 230520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 230620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 230718291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 230820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 230918291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 231020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 231130ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 231230ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 231320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 231425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 23150c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 231620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 231720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 231820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 231920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 23201acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(1); // data ref index 232120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 232220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 232320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 232420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 232520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 232620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 232720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 232820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 232920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 23300c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 233120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 233220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 233320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 233420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 233520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 233620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 233720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 233820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 233920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 234020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 234120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 23420c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 234320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 234418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2345a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificData); 2346a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificDataSize > 0); 234720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 234820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 234920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 235020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 235120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 235220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 235320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 235420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 235520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 235620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 235720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 235820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 235920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 236020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 236120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 236220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 236320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 236420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 236520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 236620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 2367050b28a593350047845a45a14cc5026221ac1620James Dong 236820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 236920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 237020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 237120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 237220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 237320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 237420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 237520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 237620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 237720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 237820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 237920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 238020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 238118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 238220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 238320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 238420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 238520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 238620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 238720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 238820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 238920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 239030ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 239151dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 239295fcef25b48e35b625899288971ab628efbf8584Andreas Huber CHECK(mCodecSpecificDataSize >= 5); 239395fcef25b48e35b625899288971ab628efbf8584Andreas Huber 239495fcef25b48e35b625899288971ab628efbf8584Andreas Huber // Patch avcc's lengthSize field to match the number 239595fcef25b48e35b625899288971ab628efbf8584Andreas Huber // of bytes we use to indicate the size of a nal unit. 239695fcef25b48e35b625899288971ab628efbf8584Andreas Huber uint8_t *ptr = (uint8_t *)mCodecSpecificData; 239795fcef25b48e35b625899288971ab628efbf8584Andreas Huber ptr[4] = 239895fcef25b48e35b625899288971ab628efbf8584Andreas Huber (ptr[4] & 0xfc) 239995fcef25b48e35b625899288971ab628efbf8584Andreas Huber | (mOwner->useNalLengthFour() ? 3 : 1); 240095fcef25b48e35b625899288971ab628efbf8584Andreas Huber 240130ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 240230ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 240330ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 240420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 240530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 24061acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox("pasp"); 24071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // This is useful if the pixel is not square 24081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // hspacing 24091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // vspacing 24101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // pasp 241130ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 241220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 241320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 241420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 241520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 241620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 24171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumSttsTableEntries); 2418c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t prevTimestampUs = 0; 2419be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 2420be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSttsTableEntries.end(); ++it) { 2421be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleCount); 2422c059860c73678a202bfa33062723e8f82fb779d9James Dong 2423c059860c73678a202bfa33062723e8f82fb779d9James Dong // Make sure that we are calculating the sample duration the exactly 2424c059860c73678a202bfa33062723e8f82fb779d9James Dong // same way as we made decision on how to create stts entries. 2425c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; 2426c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - 2427c059860c73678a202bfa33062723e8f82fb779d9James Dong (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2428c059860c73678a202bfa33062723e8f82fb779d9James Dong prevTimestampUs += (it->sampleCount * it->sampleDurationUs); 2429c059860c73678a202bfa33062723e8f82fb779d9James Dong 24308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(dur); 243120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 243220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 243320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 24341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!mIsAudio) { 2435050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("stss"); 2436050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 24371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStssTableEntries); // number of sync frames 2438050b28a593350047845a45a14cc5026221ac1620James Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2439050b28a593350047845a45a14cc5026221ac1620James Dong it != mStssTableEntries.end(); ++it) { 2440050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(*it); 2441050b28a593350047845a45a14cc5026221ac1620James Dong } 2442050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // stss 2443050b28a593350047845a45a14cc5026221ac1620James Dong } 2444050b28a593350047845a45a14cc5026221ac1620James Dong 244520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 244620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2447be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 24488644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t>::iterator it = mSampleSizes.begin(); 24498644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); // default sample size 2450be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2451be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(0); 2452be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2453ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mOwner->writeInt32(mNumSamples); 2454be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (!mSamplesHaveSameSize) { 24558644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 24568644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 24578644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); 2458be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 245920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 246020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 246120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 246220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 246320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 24641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStscTableEntries); 246513aec890216948b0c364f8f92792129d0335f506James Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 246613aec890216948b0c364f8f92792129d0335f506James Dong it != mStscTableEntries.end(); ++it) { 246713aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->firstChunk); 246813aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->samplesPerChunk); 246913aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->sampleDescriptionId); 247020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 247120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 24721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 247320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 24741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStcoTableEntries); 247513aec890216948b0c364f8f92792129d0335f506James Dong for (List<off_t>::iterator it = mChunkOffsets.begin(); 247613aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkOffsets.end(); ++it) { 24771acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (use32BitOffset) { 24781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 24791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 24801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt64((*it)); 24811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 248220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 24838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->endBox(); // stco or co64 248420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 248520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 24861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // minf 248720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 248820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 248920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 249020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 249120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2492