MPEG4Writer.cpp revision 86b7f47aa7482424cf8fd248f1315311919be3b0
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> 36674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/types.h> 37674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/stat.h> 38674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <fcntl.h> 39674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <unistd.h> 4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 4219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL; 463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 4870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongstatic const int64_t kInitialDelayTimeUs = 700000LL; 495b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong 505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// Using longer adjustment period to suppress fluctuations in 515b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// the audio encoding paths 525b6a01e65aa4129a9226667536d1bc1dad5980d8James Dongstatic const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL; // 10 minutes 533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 56bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); 578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 5820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 5920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 6137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 6237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 6325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 653b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 66d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 67b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeTrackHeader(bool use32BitOffset = true); 681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 72c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong void addChunkOffset(off64_t offset); 7370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int32_t getTrackId() const { return mTrackId; } 74dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong status_t dump(int fd, const Vector<String16>& args) const; 7520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 7720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 7820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 79693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 8020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 81a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 82a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 83eaae38445a340c4857c1c5569475879a728e63b7James Dong volatile bool mStarted; 841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 87bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t mTrackId; 88c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 8943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t mMaxChunkDurationUs; 90e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 91e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // For realtime applications, we need to adjust the media clock 92e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // for video track based on the audio media clock 93e259531ce59ab1f31de5a23124b22536f6a5a767James Dong bool mIsRealTimeRecording; 94e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t mMaxTimeStampUs; 95d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t mMdatSizeBytes; 978f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 9820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 10020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 101ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // mNumSamples is used to track how many samples in mSampleSizes List. 102ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // This is to reduce the cost associated with mSampleSizes.size() call, 103ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // since it is O(n). Ideally, the fix should be in List class. 104ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong size_t mNumSamples; 1058644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t> mSampleSizes; 106be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 107be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 10813aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 1091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStcoTableEntries; 111c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong List<off64_t> mChunkOffsets; 11213aec890216948b0c364f8f92792129d0335f506James Dong 1131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStscTableEntries; 11413aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 11513aec890216948b0c364f8f92792129d0335f506James Dong 11613aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 11713aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 11813aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 11913aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 12013aec890216948b0c364f8f92792129d0335f506James Dong 12113aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 12213aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 12313aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 12413aec890216948b0c364f8f92792129d0335f506James Dong }; 12513aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 12620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStssTableEntries; 128050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 129050b28a593350047845a45a14cc5026221ac1620James Dong 1301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumSttsTableEntries; 131be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 132be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry(uint32_t count, uint32_t durationUs) 1348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong : sampleCount(count), sampleDurationUs(durationUs) {} 135be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 136be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 1378f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong uint32_t sampleDurationUs; 138be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 140be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 1473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 1483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 1523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 1533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 1543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 157548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 15893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 15920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 16025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1613c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 16270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mStartTimeRealUs; 16370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mFirstSampleTimeRealUs; 16493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 16593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 16625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 167872a481558350634a3fd5cb67939de288af00ecbJames Dong // Has the media time adjustment for video started? 168872a481558350634a3fd5cb67939de288af00ecbJames Dong bool mIsMediaTimeAdjustmentOn; 169872a481558350634a3fd5cb67939de288af00ecbJames Dong // The time stamp when previous media time adjustment period starts 170872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustTimestampUs; 171872a481558350634a3fd5cb67939de288af00ecbJames Dong // Number of vidoe frames whose time stamp may be adjusted 172872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mMediaTimeAdjustNumFrames; 173872a481558350634a3fd5cb67939de288af00ecbJames Dong // The sample number when previous meida time adjustmnet period starts 174872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustSample; 175872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumulated drift time within a period of 176872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 177872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mTotalDriftTimeToAdjustUs; 178872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumalated drift time since the start of the recording 179872a481558350634a3fd5cb67939de288af00ecbJames Dong // excluding the current time adjustment period 180872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevTotalAccumDriftTimeUs; 181872a481558350634a3fd5cb67939de288af00ecbJames Dong 182872a481558350634a3fd5cb67939de288af00ecbJames Dong // Update the audio track's drift information. 183872a481558350634a3fd5cb67939de288af00ecbJames Dong void updateDriftTime(const sp<MetaData>& meta); 184872a481558350634a3fd5cb67939de288af00ecbJames Dong 185872a481558350634a3fd5cb67939de288af00ecbJames Dong // Adjust the time stamp of the video track according to 186872a481558350634a3fd5cb67939de288af00ecbJames Dong // the drift time information from the audio track. 187872a481558350634a3fd5cb67939de288af00ecbJames Dong void adjustMediaTime(int64_t *timestampUs); 188872a481558350634a3fd5cb67939de288af00ecbJames Dong 18920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 19037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 19120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 1933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 1943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 195b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size); 196b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size); 197b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size); 198215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 199215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 200faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 20193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 20203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 20319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 20419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 205c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 206c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 207c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 208c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 209c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 210c059860c73678a202bfa33062723e8f82fb779d9James Dong 211690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 212690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 21313f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t mRotation; 214690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void updateTrackSizeEstimate(); 2161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStscTableEntry(size_t chunkId, size_t sampleId); 2171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStssTableEntry(size_t sampleId); 2181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs); 21943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong void sendTrackSummary(bool hasMultipleTracks); 2201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 221b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Write the boxes 222b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStcoBox(bool use32BitOffset); 223b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStscBox(); 224b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStszBox(); 225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStssBox(); 226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSttsBox(); 227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeD263Box(); 228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writePaspBox(); 229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAvccBox(); 230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeUrlBox(); 231b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDrefBox(); 232b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDinfBox(); 233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDamrBox(); 234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMdhdBox(time_t now); 235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSmhdBox(); 236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVmhdBox(); 237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeHdlrBox(); 238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeTkhdBox(time_t now); 239b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4aEsdsBox(); 240b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4vEsdsBox(); 241b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAudioFourCCBox(); 242b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVideoFourCCBox(); 243b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStblBox(bool use32BitOffset); 244b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 24520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 24620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 24720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 24820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 24920111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 250674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(-1), 251674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(NO_INIT), 252b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2531acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 254a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 255a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 256a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 25720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 25813aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2597837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 26007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mInterleaveDurationUs(1000000), 26107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000(0), 26207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000(0), 26386b7f47aa7482424cf8fd248f1315311919be3b0James Dong mAreGeoTagsAvailable(false), 26486b7f47aa7482424cf8fd248f1315311919be3b0James Dong mStartTimeOffsetMs(-1) { 265674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong 26603f6f4e7e2ce09357cbc05bb546cd8a6e54b5baeJames Dong mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR); 267674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mFd >= 0) { 268674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = OK; 269674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong } 27020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 27120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 27230ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 273674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(dup(fd)), 274674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(mFd < 0? NO_INIT: OK), 275b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2761acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 277a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 278a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 279a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 28030ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 28113aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2827837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 28307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mInterleaveDurationUs(1000000), 28407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000(0), 28507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000(0), 28686b7f47aa7482424cf8fd248f1315311919be3b0James Dong mAreGeoTagsAvailable(false), 28786b7f47aa7482424cf8fd248f1315311919be3b0James Dong mStartTimeOffsetMs(-1) { 28830ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 28930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 29020111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 29120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong while (!mTracks.empty()) { 2941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong List<Track *>::iterator it = mTracks.begin(); 29520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 2961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong (*it) = NULL; 2971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mTracks.erase(it); 29820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 29920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 30020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 30120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 302dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 303dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 304dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 305dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 306dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 307dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 308dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 309dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 310dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 311dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 312dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 313dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 314dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 315dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 316dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 317dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 318dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 319dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 320dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) const { 321dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 322dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 323dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 324dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 325dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 326dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 327dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 328dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 329dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 330dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 331dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 332dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 3332dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 334bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Mutex::Autolock l(mLock); 335bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong if (mStarted) { 336bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong LOGE("Attempt to add source AFTER recording is started"); 337bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong return UNKNOWN_ERROR; 338bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong } 339bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Track *track = new Track(this, source, mTracks.size()); 34020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 3412dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 3422dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 34320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 34420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 34593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 346a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 347a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 34893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 349a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 350a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 351a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 352a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 353a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 354a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 355a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 356a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 357a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 358a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 359a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 360a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 361a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3622dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 3632dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 3642dec2b5be2056c6d9428897dc672185872d30d17James Dong // 3652dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 3662dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 3672dec2b5be2056c6d9428897dc672185872d30d17James Dong 36878a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 3692dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 37078a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 3 3712dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 3722dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 3732dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 3742dec2b5be2056c6d9428897dc672185872d30d17James Dong 3752dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 3762dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 3772dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 37878a1a286f736888ae7af8860b2c424af0d978848James Dong static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 3792dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 3802dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 3812dec2b5be2056c6d9428897dc672185872d30d17James Dong 38278a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file size limit is set 383a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 38478a1a286f736888ae7af8860b2c424af0d978848James Dong size = mMaxFileSizeLimitBytes * 6 / 1000; 38578a1a286f736888ae7af8860b2c424af0d978848James Dong } 38678a1a286f736888ae7af8860b2c424af0d978848James Dong 38778a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file duration limit is set 38878a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileDurationLimitUs != 0) { 38978a1a286f736888ae7af8860b2c424af0d978848James Dong if (bitRate > 0) { 39078a1a286f736888ae7af8860b2c424af0d978848James Dong int64_t size2 = 39178a1a286f736888ae7af8860b2c424af0d978848James Dong ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 39278a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 39378a1a286f736888ae7af8860b2c424af0d978848James Dong // When both file size and duration limits are set, 39478a1a286f736888ae7af8860b2c424af0d978848James Dong // we use the smaller limit of the two. 39578a1a286f736888ae7af8860b2c424af0d978848James Dong if (size > size2) { 39678a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 39778a1a286f736888ae7af8860b2c424af0d978848James Dong } 39878a1a286f736888ae7af8860b2c424af0d978848James Dong } else { 39978a1a286f736888ae7af8860b2c424af0d978848James Dong // Only max file duration limit is set 40078a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 40178a1a286f736888ae7af8860b2c424af0d978848James Dong } 4022dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4032dec2b5be2056c6d9428897dc672185872d30d17James Dong } 40478a1a286f736888ae7af8860b2c424af0d978848James Dong 4052dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 4062dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 4072dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4082dec2b5be2056c6d9428897dc672185872d30d17James Dong 4092dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 4102dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 4112dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 4122dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 4132dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4142dec2b5be2056c6d9428897dc672185872d30d17James Dong 415a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 4162dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 4172dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 4182dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 4192dec2b5be2056c6d9428897dc672185872d30d17James Dong} 4202dec2b5be2056c6d9428897dc672185872d30d17James Dong 4212dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 422674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 42325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 42420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 42520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 426a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong /* 427a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * Check mMaxFileSizeLimitBytes at the beginning 428a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * since mMaxFileSizeLimitBytes may be implicitly 429a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * changed later for 32-bit file offset even if 430a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * user does not ask to set it explicitly. 431a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong */ 432a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0) { 433a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested = true; 434a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong } 435a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong 4362dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 4372dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 4382dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 4392dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 4402dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 4412dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4422dec2b5be2056c6d9428897dc672185872d30d17James Dong 4431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mUse32BitOffset) { 4441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // Implicit 32 bit file size limit 4451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes == 0) { 4461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4471f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 4491f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // If file size is set to be larger than the 32 bit file 4501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // size limit, treat it as an error. 4511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 452872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGW("32-bit file size limit (%lld bytes) too big. " 453d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong "It is changed to %lld bytes", 454d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes, kMax32BitFileSize); 455d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 459b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong int32_t use2ByteNalLength; 460b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (param && 461b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 462b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong use2ByteNalLength) { 463b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength = false; 4642dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4652dec2b5be2056c6d9428897dc672185872d30d17James Dong 466065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 46793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 468a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 469a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 470a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 47193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 472a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 473a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 474a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 475a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 4768f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 4778f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 4788f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 4798f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 4808f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 4818f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 4828f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 4837837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 4847837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 4857837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 4867837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4877837c17063a4c50bc856ba59418516fdab731de7James Dong 488b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFtypBox(param); 48920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4907837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 49120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4927837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 4932dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 4942dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 4952dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 4962dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4972dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 4987837c17063a4c50bc856ba59418516fdab731de7James Dong } 4997837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 500c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 5017837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 5027837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 5037837c17063a4c50bc856ba59418516fdab731de7James Dong 5047837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 5057837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 506c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 5071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 5081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 5091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 5101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 5111acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 5121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 5141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 5151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 5161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 5171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 519a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 520a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 52120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 5221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 523a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 52425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 52520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 52620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const { 5281f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong return mUse32BitOffset; 5291f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 5301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 53137187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 532674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 53337187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 534a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 535a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 53637187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 537a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 538a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 53937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 54037187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 54137187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 54237187916a486504acaf83bea30147eb5fbf46ae5James Dong } 543a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 54437187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 545a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 546a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 5471c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 548cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping writer thread"); 5491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 5511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 5521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 5541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 5551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 5561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 5581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 559cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Writer thread stopped"); 5601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 5611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 56213f6284305e4b27395a23db7882d670bdb1bcae1James Dong/* 56313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix: 56413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a b u | 56513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c d v | 56613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x y w | 56713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * 56813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following 56913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w}, 57013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while 57113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format. 57213f6284305e4b27395a23db7882d670bdb1bcae1James Dong */ 57313f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) { 57413f6284305e4b27395a23db7882d670bdb1bcae1James Dong LOGV("writeCompositionMatrix"); 57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t a = 0x00010000; 57613f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t b = 0; 57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t c = 0; 57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t d = 0x00010000; 57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong switch (degrees) { 58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 0: 58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 90: 58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 58413f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0x00010000; 58513f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0xFFFF0000; 58613f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 58713f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 58813f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 180: 58913f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0xFFFF0000; 59013f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0xFFFF0000; 59113f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 59213f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 270: 59313f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 59413f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0xFFFF0000; 59513f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0x00010000; 59613f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 59713f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 59813f6284305e4b27395a23db7882d670bdb1bcae1James Dong default: 59913f6284305e4b27395a23db7882d670bdb1bcae1James Dong CHECK(!"Should never reach this unknown rotation"); 60013f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 60113f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 60213f6284305e4b27395a23db7882d670bdb1bcae1James Dong 60313f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(a); // a 60413f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(b); // b 60513f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // u 60613f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(c); // c 60713f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(d); // d 60813f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // v 60913f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // x 61013f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // y 61113f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0x40000000); // w 61213f6284305e4b27395a23db7882d670bdb1bcae1James Dong} 61313f6284305e4b27395a23db7882d670bdb1bcae1James Dong 61413f6284305e4b27395a23db7882d670bdb1bcae1James Dong 61537187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() { 616674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 61737187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 61820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 61920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 62037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 6218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 62265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong int64_t minDurationUs = 0x7fffffffffffffffLL; 62320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 62420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 62537187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 62637187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 62737187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 62837187916a486504acaf83bea30147eb5fbf46ae5James Dong } 62920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 6318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 6328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 63320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 63465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (durationUs < minDurationUs) { 63565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs = durationUs; 63665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 63765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 63865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong 63965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (mTracks.size() > 1) { 64065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong LOGD("Duration from tracks range is [%lld, %lld] us", 64165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs, maxDurationUs); 64220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 6457837c17063a4c50bc856ba59418516fdab731de7James Dong 64637187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 64737187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 648674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 649674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 650674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 65137187916a486504acaf83bea30147eb5fbf46ae5James Dong mStarted = false; 65237187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 65337187916a486504acaf83bea30147eb5fbf46ae5James Dong } 65437187916a486504acaf83bea30147eb5fbf46ae5James Dong 65520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 6561acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 657c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 6581acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 659c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 4); 6601acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 661c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset + 8, SEEK_SET); 6621acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 6631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 664c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 8); 6651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 666c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 66720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 668c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong const off64_t moovOffset = mOffset; 6697837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 6707837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 6717837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6727837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMoovBox(maxDurationUs); 67420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6757837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6767837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 6777837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 6787837c17063a4c50bc856ba59418516fdab731de7James Dong 6797837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 680c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 6817837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 682674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 6837837c17063a4c50bc856ba59418516fdab731de7James Dong 6847837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 685c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 6867837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 6877837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 6887837c17063a4c50bc856ba59418516fdab731de7James Dong 6897837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 6907837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 6917837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6927837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6932dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 6942dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 6957837c17063a4c50bc856ba59418516fdab731de7James Dong } 6967837c17063a4c50bc856ba59418516fdab731de7James Dong 6970c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 699674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 700674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 701674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 702a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 70370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 70437187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 70520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 70620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) { 708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong time_t now = time(NULL); 709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("mvhd"); 710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // version=0, flags=0 711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // creation time 712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // modification time 713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTimeScale); // mvhd timescale 714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; 715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(duration); 716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0x10000); // rate: 1.0 717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0x100); // volume 718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0); // reserved 719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeCompositionMatrix(0); // matrix 722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTracks.size() + 1); // nextTrackID 729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // mvhd 730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) { 733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("moov"); 734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMvhdBox(durationUs); 73507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (mAreGeoTagsAvailable) { 73607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeUdtaBox(); 73707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t id = 1; 739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<Track *>::iterator it = mTracks.begin(); 740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mTracks.end(); ++it, ++id) { 741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (*it)->writeTrackHeader(mUse32BitOffset); 742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // moov 744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 7464650ff0e86f9e815e3152a806a06c700418d071dJames Dongvoid MPEG4Writer::writeFtypBox(const MetaData *param) { 747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("ftyp"); 748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t fileType; 750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (param && param->findInt32(kKeyFileType, &fileType) && 751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fileType != OUTPUT_FORMAT_MPEG_4) { 752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("3gp4"); 753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("isom"); 755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); 758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("isom"); 759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("3gp4"); 760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); 761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 76370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() { 76470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 76570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it != mChunkInfos.end(); ++it) { 76670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int trackNum = it->mTrack->getTrackId() << 28; 76770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 76870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, 76970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs); 77070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 77170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong} 77270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 77313aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 77413aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 77513aec890216948b0c364f8f92792129d0335f506James Dong return OK; 77613aec890216948b0c364f8f92792129d0335f506James Dong} 77713aec890216948b0c364f8f92792129d0335f506James Dong 77813aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 77913aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 78013aec890216948b0c364f8f92792129d0335f506James Dong} 78113aec890216948b0c364f8f92792129d0335f506James Dong 78213aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 78313aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 78413aec890216948b0c364f8f92792129d0335f506James Dong} 78520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 786c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 787c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 78820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 789c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 790c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 791c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong buffer->range_length()); 79220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 79320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 79420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 79520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 79620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 79720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 79803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 79903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 80003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 80103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 80203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 80303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 80403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 80503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 80603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 80703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 80803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 80903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 81003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 81103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 812c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 813c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 81430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 81530ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 81603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 817b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mUse4ByteNalLength) { 818b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 24; 819c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 820b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 16) & 0xff; 821c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 822b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 8) & 0xff; 823c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 824b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 825c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 826c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong 827c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 828c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 829c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong length); 830b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 831b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 4; 832b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 833b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong CHECK(length < 65536); 83430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 835b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 8; 836c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 837b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 838c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 839c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 840b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 2; 841b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 84230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 84330ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 84430ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 84530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 8467837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 847674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong const void *ptr, size_t size, size_t nmemb) { 8487837c17063a4c50bc856ba59418516fdab731de7James Dong 8497837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 8507837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 851674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // This happens only when we write the moov box at the end of 852674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // recording, not for each output video/audio frame we receive. 853c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 8541acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 855c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mBoxes.begin(); 8567837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 8577837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 8587837c17063a4c50bc856ba59418516fdab731de7James Dong } 859674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong lseek64(mFd, mOffset, SEEK_SET); 860674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 861674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 8627837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 8637837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 8647837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 8657837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 8667837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 8677837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 8687837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 8697837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 8707837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 8717837c17063a4c50bc856ba59418516fdab731de7James Dong } 8727837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 873674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 8747837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 8757837c17063a4c50bc856ba59418516fdab731de7James Dong } 8767837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 8777837c17063a4c50bc856ba59418516fdab731de7James Dong} 8787837c17063a4c50bc856ba59418516fdab731de7James Dong 87920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 8800c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 88120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8827837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 8837837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 88420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 88520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 88620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 88720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 88820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 88920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 8900c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 89120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 892c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = *--mBoxes.end(); 89320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 89420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8957837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 8967837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 8977837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 8987837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 899c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, offset, SEEK_SET); 9007837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 9017837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 902c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 9037837c17063a4c50bc856ba59418516fdab731de7James Dong } 90420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 90520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 90620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 907674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 1); 90820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 91120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 912674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 2); 91320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 91420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 91520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 91620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 917674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 4); 91820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 91920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 92120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 922674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 8); 92320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 927674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, n + 1); 92820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 92920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 93020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 9310c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 932674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, 4); 93320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 93420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 93507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 93607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format 93707b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) { 93807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 93907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 94007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 94107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 94207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[9]; 94307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 94407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 94507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%c%.2d.", sign, wholePart); 94607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 94707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%+.2d.", wholePart); 94807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 94907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 95007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 95107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 95207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 95307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 95407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 95507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[4], 5, "%.4d", fractionalPart); 95607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 95707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 95807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 8); 95907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 96007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 96107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format 96207b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) { 96307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 96407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 96507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 96607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 96707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[10]; 96807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 96907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 97007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%c%.3d.", sign, wholePart); 97107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 97207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%+.3d.", wholePart); 97307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 97407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 97507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 97607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 97707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 97807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 97907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 98007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[5], 5, "%.4d", fractionalPart); 98107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 98207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 98307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 9); 98407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 98507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 98607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 98707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 98807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and 98907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000. 99007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and 99107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180] 99207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 99307b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { 99407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Is latitude or longitude out of range? 99507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (latitudex10000 < -900000 || latitudex10000 > 900000 || 99607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong longitudex10000 < -1800000 || longitudex10000 > 1800000) { 99707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return BAD_VALUE; 99807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 99907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 100007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000 = latitudex10000; 100107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000 = longitudex10000; 100207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mAreGeoTagsAvailable = true; 100307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return OK; 100407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 100507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 100620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 1007674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(data, 1, size); 100820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 100920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 101078a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const { 101178a1a286f736888ae7af8860b2c424af0d978848James Dong return mStreamableFile; 101278a1a286f736888ae7af8860b2c424af0d978848James Dong} 101378a1a286f736888ae7af8860b2c424af0d978848James Dong 1014d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 1015d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1016d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 1017d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1018d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1019d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1020956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 1021d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1022d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1023d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1024d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 10251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1026acd234bba9f048971d66890009eeff9a8db94be3James Dong // Be conservative in the estimate: do not exceed 95% of 1027acd234bba9f048971d66890009eeff9a8db94be3James Dong // the target file limit. For small target file size limit, though, 1028acd234bba9f048971d66890009eeff9a8db94be3James Dong // this will not help. 1029acd234bba9f048971d66890009eeff9a8db94be3James Dong return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 1030d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1031d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1032d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 1033d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1034d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 1035d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1036d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1037d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1038d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1039d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1040d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 1041d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 1042d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1043d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1044d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1045d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1046d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 104725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 104825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 104925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 105025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 105125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 105225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 105325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 105425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 105525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 105625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 105725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 105825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 105925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 1060f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 1061f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 1062f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 10633c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 1064065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 1065f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 1066f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 10673c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 10683c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 10693c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 1070f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 10713c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 10723c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 10733c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 10743c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 107558ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 107658ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 107758ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 107858ae9c530247668f8af36e30d228c716c226b3d4James Dong} 107958ae9c530247668f8af36e30d228c716c226b3d4James Dong 108020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 108120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 108220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 1083bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) 108420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 108525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 108620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 108720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 1088a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 1089a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 1090eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted(false), 1091bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mTrackId(trackId), 1092c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 1093956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 1094be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 109520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 109625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 1097548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 109813f6284305e4b27395a23db7882d670bdb1bcae1James Dong mReachedEOS(false), 109913f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation(0) { 110019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 11018f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 11021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 11031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 11041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 11051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 11061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 11071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 11081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1109c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 1110c059860c73678a202bfa33062723e8f82fb779d9James Dong} 1111c059860c73678a202bfa33062723e8f82fb779d9James Dong 11121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() { 11131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset() 11151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ? mNumStcoTableEntries * 4 11161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong : mNumStcoTableEntries * 8; 11171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4); 11191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 112078a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 112178a1a286f736888ae7af8860b2c424af0d978848James Dong if (!mOwner->isFileStreamable()) { 112278a1a286f736888ae7af8860b2c424af0d978848James Dong // Reserved free space is not large enough to hold 112378a1a286f736888ae7af8860b2c424af0d978848James Dong // all meta data and thus wasted. 112478a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 + // stsc box size 112578a1a286f736888ae7af8860b2c424af0d978848James Dong mNumStssTableEntries * 4 + // stss box size 112678a1a286f736888ae7af8860b2c424af0d978848James Dong mNumSttsTableEntries * 8 + // stts box size 112778a1a286f736888ae7af8860b2c424af0d978848James Dong stcoBoxSizeBytes + // stco box size 112878a1a286f736888ae7af8860b2c424af0d978848James Dong stszBoxSizeBytes; // stsz box size 112978a1a286f736888ae7af8860b2c424af0d978848James Dong } 11301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry( 11331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t chunkId, size_t sampleId) { 11341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong StscTableEntry stscEntry(chunkId, sampleId, 1); 11361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStscTableEntries.push_back(stscEntry); 11371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStscTableEntries; 11381f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11401f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 11411f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStssTableEntries.push_back(sampleId); 11421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStssTableEntries; 11431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry( 11461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t sampleCount, int64_t durationUs) { 11471f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong SttsTableEntry sttsEntry(sampleCount, durationUs); 11491f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mSttsTableEntries.push_back(sttsEntry); 11501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumSttsTableEntries; 11511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1153c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) { 11541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStcoTableEntries; 11551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mChunkOffsets.push_back(offset); 11561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1158c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 1159c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 1160c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 1161c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 1162c059860c73678a202bfa33062723e8f82fb779d9James Dong 1163c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 1164c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 1165c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 1166c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1167c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 1168c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 1169c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1170c059860c73678a202bfa33062723e8f82fb779d9James Dong 1171c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 1172c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 1173c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1174c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 1175c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1176c059860c73678a202bfa33062723e8f82fb779d9James Dong 11778f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 117819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 117919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 118019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 118119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 118219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 118319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 118419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 118519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 118619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 118719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 118819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 118919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 119019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 119119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 119219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 119319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 119419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 119519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 119619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 119719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 119819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 119919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 120019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 120119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 120219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 120319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 120419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 120519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 120619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 120719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 120819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 120920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 121020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 121120111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 121220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 121320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 121420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 121520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 121620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 121720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 121820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 121920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 122093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 122193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 122293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 122393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 122493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 122593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 122693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 122793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 122893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 122993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 123093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 123193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 123293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 123393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 123493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 12351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 12361c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 12371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 12381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 12391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 12401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 12411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12431c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 12441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 12451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 12461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 12471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 12491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 12501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 12521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 12531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 12541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 12551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 12591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1261fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) { 1262fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("writeChunkToFile: %lld from %s track", 1263fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video"); 1264fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1265fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong int32_t isFirstSample = true; 1266fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!chunk->mSamples.empty()) { 1267fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 1268fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1269fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong off64_t offset = chunk->mTrack->isAvc() 1270fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong ? addLengthPrefixedSample_l(*it) 1271fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong : addSample_l(*it); 1272fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1273fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (isFirstSample) { 1274fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mTrack->addChunkOffset(offset); 1275fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong isFirstSample = false; 12761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 12791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 1280fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.erase(it); 12811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1282fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.clear(); 12831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1285fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() { 1286fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("writeAllChunks"); 12871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 128870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong Chunk chunk; 128970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong while (findChunkToWrite(&chunk)) { 129070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong ++outstandingChunks; 12911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 129270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 129370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong sendSessionSummary(); 129470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 12951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 12961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 12971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1299fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 1300fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("findChunkToWrite"); 13011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 13031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 13041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 13051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 13061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 13071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 13081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 13091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 13101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 13111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 13161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 1317fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 13181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 13211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 13221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1323fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 13241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 13251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 13261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 1327fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong *chunk = *(it->mChunks.begin()); 1328fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong it->mChunks.erase(it->mChunks.begin()); 1329fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong CHECK_EQ(chunk->mTrack, track); 133070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 133170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t interChunkTimeUs = 133270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 133370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 133470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs = interChunkTimeUs; 133570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 133670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 1337fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return true; 13381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1340fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1341fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 13421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 13431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13441c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 13451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 13461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1347a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 1348fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1349fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Mutex::Autolock autoLock(mLock); 13501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 1351fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Chunk chunk; 1352fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong bool chunkFound = false; 1353fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1354fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 13551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 13561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1358fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong // Actual write without holding the lock in order to 1359fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong // reduce the blocking time for media track threads. 1360fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (chunkFound) { 1361fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong mLock.unlock(); 1362fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeChunkToFile(&chunk); 1363fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong mLock.lock(); 1364fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong } 13651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1366fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1367fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeAllChunks(); 13681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 13691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13701c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 13711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 13721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 13741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1375e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 13761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 13771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 13781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 13791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 138070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mPrevChunkTimestampUs = 0; 138170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mMaxInterChunkDurUs = 0; 13821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 13831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 13861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 13871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 13881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 13891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 13901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 13911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 13921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 139493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1395a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1396a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1397a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1398a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1399a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 140025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 140193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 140219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 140319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 140419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 140570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mStartTimeRealUs = startTimeUs; 140619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 140713f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t rotationDegrees; 140813f6284305e4b27395a23db7882d670bdb1bcae1James Dong if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 140913f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation = rotationDegrees; 141013f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 141113f6284305e4b27395a23db7882d670bdb1bcae1James Dong 14125b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong mIsRealTimeRecording = true; 1413e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1414e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1415e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1416e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1417e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1418e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1419e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 142093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 142193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1422f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1423a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mIsRealTimeRecording && mOwner->numTracks() > 1) { 1424a472613aec322e25891abf5c77bf3f7e3c244920James Dong /* 1425a472613aec322e25891abf5c77bf3f7e3c244920James Dong * This extra delay of accepting incoming audio/video signals 1426a472613aec322e25891abf5c77bf3f7e3c244920James Dong * helps to align a/v start time at the beginning of a recording 1427a472613aec322e25891abf5c77bf3f7e3c244920James Dong * session, and it also helps eliminate the "recording" sound for 1428a472613aec322e25891abf5c77bf3f7e3c244920James Dong * camcorder applications. 1429a472613aec322e25891abf5c77bf3f7e3c244920James Dong * 143086b7f47aa7482424cf8fd248f1315311919be3b0James Dong * If client does not set the start time offset, we fall back to 143186b7f47aa7482424cf8fd248f1315311919be3b0James Dong * use the default initial delay value. 1432a472613aec322e25891abf5c77bf3f7e3c244920James Dong */ 143386b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 143486b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 143586b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 143686b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 143786b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeUs += startTimeOffsetUs; 143886b7f47aa7482424cf8fd248f1315311919be3b0James Dong LOGI("Start time offset: %lld us", startTimeOffsetUs); 1439a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 1440a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1441f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1442a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1443f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 144425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 144525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 144625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 144725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 144820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 144920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 145020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 145120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 145220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 145320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1454eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted = true; 1455c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 145625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1457956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 14581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStcoTableEntries = 0; 14591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStssTableEntries = 0; 14601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStscTableEntries = 0; 14611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumSttsTableEntries = 0; 14621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes = 0; 1463872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = false; 1464872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = 0; 1465872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 0; 1466872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = 0; 1467872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 0; 1468872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = 0; 146943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = 0; 147020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 147125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 147220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 147325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 147425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 147520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 147620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 147737187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1478a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 147937187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1480a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1481a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 148237187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 1483cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track", mIsAudio? "Audio": "Video"); 1484eaae38445a340c4857c1c5569475879a728e63b7James Dong if (!mStarted) { 1485eaae38445a340c4857c1c5569475879a728e63b7James Dong LOGE("Stop() called but track is not started"); 1486eaae38445a340c4857c1c5569475879a728e63b7James Dong return ERROR_END_OF_STREAM; 1487eaae38445a340c4857c1c5569475879a728e63b7James Dong } 1488eaae38445a340c4857c1c5569475879a728e63b7James Dong 148920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 149037187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 149120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 149220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 149320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 149420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 149520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 149620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 149737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = (status_t) dummy; 149837187916a486504acaf83bea30147eb5fbf46ae5James Dong 1499cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track source", mIsAudio? "Audio": "Video"); 150037187916a486504acaf83bea30147eb5fbf46ae5James Dong { 150137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = mSource->stop(); 150237187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { 150337187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 150437187916a486504acaf83bea30147eb5fbf46ae5James Dong } 150537187916a486504acaf83bea30147eb5fbf46ae5James Dong } 150637187916a486504acaf83bea30147eb5fbf46ae5James Dong 1507cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("%s track stopped", mIsAudio? "Audio": "Video"); 150837187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 150920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 151020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 151125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 151225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 151325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 151425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 151520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 151620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 151720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 151820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 151937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 152037187916a486504acaf83bea30147eb5fbf46ae5James Dong return (void *) err; 152120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 152220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 15233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 15243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 15253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 15273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 15283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 15293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 15313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 15323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 15343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 15363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 15373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 15383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 15393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 15413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 15423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 15443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 15453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 15543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 15553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 15563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 15573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 15583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 15613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 15623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 15633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 15643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 15653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 15673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 15683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 15693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 15703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 15713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 15723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 15733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 15743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 15753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 15763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 15793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 15803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 15813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 15833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 15843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 15863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 15873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 15883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 15903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 15913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 15923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 15933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 15943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 15973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 15983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 15993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 16003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 16013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 16033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 16043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 16063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 16073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 16083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 16093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 16103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 16113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 16123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 16133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 16143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 16153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 16163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 16173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 16183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 16193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 16203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 16213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 16223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 16253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 16263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 16283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 16293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 16303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 16313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 16343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 16353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 16373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 16383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 16393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 16433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 16473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 16483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 16493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 16503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 16533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 16543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 16553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 16563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 16573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 16613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 16623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 16673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 16683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 16693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 16703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 16713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 16743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 16753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 16803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 16813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 16823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 16833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 16843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 16853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 16863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 16903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1691548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 169203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 169303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1694548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 169503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1696548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 169703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 169803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 169903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 17013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 170203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 170303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 170403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 17063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 17073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 170803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 170903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 171103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 171203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 171303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 17153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 171603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 171703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 17183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 17193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 17203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 17213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 172203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 1724b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1725b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 3; // length size == 4 bytes 1726b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1727b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 1; // length size == 2 bytes 1728b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 172903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 17313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 17323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 17333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 17343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 17353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 17363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 17373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 17383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 17393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 17403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 17423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 17433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 17443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 17453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 17473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 17483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 17493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 17503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 17513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 17523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 17533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 17543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 17553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 17563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 17583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 17593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 17603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 176103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 176203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 176303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 176403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1765872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1766872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications 1767872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows: 1768872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1769872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of 1770872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs 1771872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of 1772872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small 1773872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value 1774872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding 1775872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep 1776872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the 1777872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is 1778872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track. 1779872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1780872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found 1781872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed 1782872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames 1783872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames 1784872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period. 1785872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion 1786872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames 1787872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is 1788872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media 1789872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a 1790872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5). 1791872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1792872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that 1793872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift. 1794872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time 1795872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold 1796872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs. 1797872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental 1798872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the 1799872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift. 1800872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio 1801872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of 1802872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold 1803872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of 1804872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio 1805872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time 1806872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no 1807872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time 1808872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some 1809872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want 1810872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being. 1811872a481558350634a3fd5cb67939de288af00ecbJames Dong*/ 1812872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) { 1813872a481558350634a3fd5cb67939de288af00ecbJames Dong if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >= 1814872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs) { 1815872a481558350634a3fd5cb67939de288af00ecbJames Dong 1816872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("New media time adjustment period at %lld us", *timestampUs); 1817872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = true; 1818872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 1819872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample) >> 1; 1820872a481558350634a3fd5cb67939de288af00ecbJames Dong 1821872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = *timestampUs; 1822872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = mNumSamples; 1823872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs(); 1824872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 1825872a481558350634a3fd5cb67939de288af00ecbJames Dong totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs; 1826872a481558350634a3fd5cb67939de288af00ecbJames Dong 1827872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs; 1828872a481558350634a3fd5cb67939de288af00ecbJames Dong 1829872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on incremental adjusted time per frame 1830872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t adjustTimePerFrameUs = 1831872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames; 1832872a481558350634a3fd5cb67939de288af00ecbJames Dong 1833872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs < 0) { 1834872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs = -adjustTimePerFrameUs; 1835872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1836872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs >= 5000) { 1837872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Adjusted time per video frame is %lld us", 1838872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs); 1839872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"Video frame time adjustment is too large!"); 1840872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1841872a481558350634a3fd5cb67939de288af00ecbJames Dong 1842872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on total accumulated time drift within a period of 1843872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 1844872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000) 1845872a481558350634a3fd5cb67939de288af00ecbJames Dong / kVideoMediaTimeAdjustPeriodTimeUs; 1846872a481558350634a3fd5cb67939de288af00ecbJames Dong 1847872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage < 0) { 1848872a481558350634a3fd5cb67939de288af00ecbJames Dong driftPercentage = -driftPercentage; 1849872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1850872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage > 5) { 1851872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Audio track has time drift %lld us over %lld us", 1852872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs, 1853872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs); 1854872a481558350634a3fd5cb67939de288af00ecbJames Dong 1855872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"The audio track media time drifts too much!"); 1856872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1857872a481558350634a3fd5cb67939de288af00ecbJames Dong 1858872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1859872a481558350634a3fd5cb67939de288af00ecbJames Dong 1860872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsMediaTimeAdjustmentOn) { 1861872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mNumSamples - mPrevMediaTimeAdjustSample <= 1862872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames) { 1863872a481558350634a3fd5cb67939de288af00ecbJames Dong 1864872a481558350634a3fd5cb67939de288af00ecbJames Dong // Do media time incremental adjustment 1865872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t incrementalAdjustTimeUs = 1866872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs * 1867872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample)) 1868872a481558350634a3fd5cb67939de288af00ecbJames Dong / mMediaTimeAdjustNumFrames; 1869872a481558350634a3fd5cb67939de288af00ecbJames Dong 1870872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1871872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs); 1872872a481558350634a3fd5cb67939de288af00ecbJames Dong 1873872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Incremental video frame media time adjustment: %lld us", 1874872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs)); 1875872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1876872a481558350634a3fd5cb67939de288af00ecbJames Dong // Within the remaining adjustment period, 1877872a481558350634a3fd5cb67939de288af00ecbJames Dong // no incremental adjustment is needed. 1878872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1879872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs); 1880872a481558350634a3fd5cb67939de288af00ecbJames Dong 1881872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Fixed video frame media time adjustment: %lld us", 1882872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs)); 1883872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1884872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1885872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1886872a481558350634a3fd5cb67939de288af00ecbJames Dong 1887872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1888872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that 1889872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information 1890872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio 1891872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger 1892872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 1893872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined. 1894872a481558350634a3fd5cb67939de288af00ecbJames Dong */ 1895872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 1896872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftTimeUs = 0; 1897872a481558350634a3fd5cb67939de288af00ecbJames Dong if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 1898872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 1899872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 1900872a481558350634a3fd5cb67939de288af00ecbJames Dong mOwner->setDriftTimeUs(timeUs); 1901872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1902872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1903872a481558350634a3fd5cb67939de288af00ecbJames Dong 190437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 190530ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 190613aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 190743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong const bool hasMultipleTracks = (mOwner->numTracks() > 1); 190813aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 190913aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 191013aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 19118f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 19128f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1913c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1914c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 19158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1916be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1917a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 19181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1919e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1920a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong if (mIsAudio) { 1921a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 1922a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } else { 1923a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 1924a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } 1925985f838934510983d8a887461e98dca60a6e858fJames Dong setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); 1926985f838934510983d8a887461e98dca60a6e858fJames Dong 1927d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 192820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1929ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 193093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 193120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 193293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 193320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 193420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 193520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 193613aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 193720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 193820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 193920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1940a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1941a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1942a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1943a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1944a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1945a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1946a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1947a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1948a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 194930ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 195030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 195103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 195203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 195303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1954548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1955548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 19561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 195703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 195803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 195903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 196003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1961be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 19621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 196303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 196403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 196503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 196603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 196703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 196803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 196930ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 197030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 197130ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 197230ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 197330ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1974548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 197530ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 1976a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1977a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1978d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 1979d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 1980d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1981d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1982d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 1983d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 1984d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 1985d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 1986d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 1987d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 19881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 1989e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 1990b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong size_t sampleSize = copy->range_length(); 1991b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mIsAvc) { 1992b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1993b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 4; 1994b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1995b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 2; 1996b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1997b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1998050b28a593350047845a45a14cc5026221ac1620James Dong 1999d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 20001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes += sampleSize; 20011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong updateTrackSizeEstimate(); 20021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 2003d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 2004d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2005d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2006d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2007d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 2008d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2009d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2010d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2011d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2012050b28a593350047845a45a14cc5026221ac1620James Dong 2013d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 2014d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2015d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 20168428af5381e835cc783b7ecb0d71cb60961c99c2James Dong /* 20178428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The original timestamp found in the data buffer will be modified as below: 20188428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20198428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * There is a playback offset into this track if the track's start time 20208428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is not the same as the movie start time, which will be recorded in edst 20218428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * box of the output file. The playback offset is to make sure that the 20228428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * starting time of the audio/video tracks are synchronized. Although the 20238428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * track's media timestamp may be subject to various modifications 20248428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * as outlined below, the track's playback offset time remains unchanged 20258428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * once the first data buffer of the track is received. 20268428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20278428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The media time stamp will be calculated by subtracting the playback offset 20288428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * (and potential pause durations) from the original timestamp in the buffer. 20298428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20308428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If this track is a video track for a real-time recording application with 20318428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * both audio and video tracks, its media timestamp will subject to further 20328428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * modification based on the media clock of the audio track. This modification 20338428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is needed for the purpose of maintaining good audio/video synchronization. 20348428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20358428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If the recording session is paused and resumed multiple times, the track 20368428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * media timestamp will be modified as if the recording session had never been 20378428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * paused at all during playback of the recorded output file. In other words, 20388428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * the output file will have no memory of pause/resume durations. 20398428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20408428af5381e835cc783b7ecb0d71cb60961c99c2James Dong */ 2041d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 20428428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs); 2043d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 2044d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 204570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (mNumSamples == 0) { 204670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mFirstSampleTimeRealUs = systemTime() / 1000; 2047f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 2048f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 20498428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs = mStartTimestampUs; 20503c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 205148c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 2052a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 20538428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 20548428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(durExcludingEarlierPausesUs >= 0); 20558428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 20568428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(pausedDurationUs >= lastDurationUs); 20578428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs += pausedDurationUs - lastDurationUs; 2058a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 2059a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2060a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2061a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 20628428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(timestampUs >= 0); 2063872a481558350634a3fd5cb67939de288af00ecbJames Dong 2064872a481558350634a3fd5cb67939de288af00ecbJames Dong // Media time adjustment for real-time applications 2065872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsRealTimeRecording) { 2066872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2067872a481558350634a3fd5cb67939de288af00ecbJames Dong updateDriftTime(meta_data); 2068872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 2069872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustMediaTime(×tampUs); 2070e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2071e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2072872a481558350634a3fd5cb67939de288af00ecbJames Dong 2073e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 2074e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 2075e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 20764f86a980fee1880dca61b828599fa6d76755a485James Dong LOGW("Frame arrives too late!"); 20774f86a980fee1880dca61b828599fa6d76755a485James Dong // Don't drop the late frame, since dropping a frame may cause 20784f86a980fee1880dca61b828599fa6d76755a485James Dong // problems later during playback 20794f86a980fee1880dca61b828599fa6d76755a485James Dong 20804f86a980fee1880dca61b828599fa6d76755a485James Dong // The idea here is to avoid having two or more samples with the 20814f86a980fee1880dca61b828599fa6d76755a485James Dong // same timestamp in the output file. 20824f86a980fee1880dca61b828599fa6d76755a485James Dong if (mTimeScale >= 1000000LL) { 208340e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + 1; 20844f86a980fee1880dca61b828599fa6d76755a485James Dong } else { 208540e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale; 20864f86a980fee1880dca61b828599fa6d76755a485James Dong } 2087e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2088e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2089e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 20908428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s media time stamp: %lld and previous paused duration %lld", 20918428af5381e835cc783b7ecb0d71cb60961c99c2James Dong mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); 2092c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 2093c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 20943b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 20953b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 20968644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 2097ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 2098ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 2099c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 2100c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 2101c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 2102c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 2103c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 2104c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 2105c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 2106c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2107c059860c73678a202bfa33062723e8f82fb779d9James Dong 2108a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Force the first sample to have its own stts entry so that 2109a472613aec322e25891abf5c77bf3f7e3c244920James Dong // we can adjust its value later to maintain the A/V sync. 2110a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) { 2111a472613aec322e25891abf5c77bf3f7e3c244920James Dong LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us", 2112a472613aec322e25891abf5c77bf3f7e3c244920James Dong mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks); 21131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 2114be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 2115be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2116be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 2117be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2118be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2119be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 2120ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 2121be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 2122be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 21238644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 2124be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2125a472613aec322e25891abf5c77bf3f7e3c244920James Dong LOGV("%s timestampUs/lastTimestampUs: %lld/%lld", 2126a472613aec322e25891abf5c77bf3f7e3c244920James Dong mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs); 21278644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 2128c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 21298644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 213020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2131d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 21321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStssTableEntry(mNumSamples); 2133d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 2134d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 213593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 213693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 213793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 213893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 2139faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 214093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 214143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 2142c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 214358ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 214458ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 21451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addChunkOffset(offset); 214658ae9c530247668f8af36e30d228c716c226b3d4James Dong } 214758ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 214858ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 214958ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 215058ae9c530247668f8af36e30d228c716c226b3d4James Dong } 215113aec890216948b0c364f8f92792129d0335f506James Dong 215213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 215313aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 21541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, 1); 21551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 215613aec890216948b0c364f8f92792129d0335f506James Dong } else { 215713aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 215813aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 215913aec890216948b0c364f8f92792129d0335f506James Dong } else { 216043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 216143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > interleaveDurationUs) { 216243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > mMaxChunkDurationUs) { 216343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = chunkDurationUs; 216443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 216513aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 216613aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 216713aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 216813aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 21691f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(nChunks, mChunkSamples.size()); 217013aec890216948b0c364f8f92792129d0335f506James Dong } 21711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 217213aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 217313aec890216948b0c364f8f92792129d0335f506James Dong } 217413aec890216948b0c364f8f92792129d0335f506James Dong } 217513aec890216948b0c364f8f92792129d0335f506James Dong } 217613aec890216948b0c364f8f92792129d0335f506James Dong 217720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 217825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 2179a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong if (mSampleSizes.empty() || // no samples written 2180a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (!mIsAudio && mNumStssTableEntries == 0) || // no sync frames for video 2181a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (OK != checkCodecSpecificData())) { // no codec specific data 2182690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 2183f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 2184bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, -1, err); 2185be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 218613aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 218743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 21881f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(1, mNumSamples); 218958ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 21901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, mChunkSamples.size()); 21911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 219213aec890216948b0c364f8f92792129d0335f506James Dong } 219313aec890216948b0c364f8f92792129d0335f506James Dong 2194be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 2195be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 2196be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 2197ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 21988f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 2199be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2200be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 2201be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2202a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2203a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mNumSamples <= 2) { 2204a472613aec322e25891abf5c77bf3f7e3c244920James Dong addOneSttsTableEntry(1, lastDurationUs); 2205a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (sampleCount - 1 > 0) { 2206a472613aec322e25891abf5c77bf3f7e3c244920James Dong addOneSttsTableEntry(sampleCount - 1, lastDurationUs); 2207a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2208a472613aec322e25891abf5c77bf3f7e3c244920James Dong } else { 2209a472613aec322e25891abf5c77bf3f7e3c244920James Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 2210a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2211a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2212c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 221325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 221443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 221543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong sendTrackSummary(hasMultipleTracks); 221643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 22171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 22181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video"); 2219872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2220872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); 2221872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2222365a963142093a1cd8efdcea76b5f65096a5b115James Dong 222337187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 222437187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 222537187916a486504acaf83bea30147eb5fbf46ae5James Dong } 222637187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 2227365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 2228365a963142093a1cd8efdcea76b5f65096a5b115James Dong 222943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 223043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int trackNum = (mTrackId << 28); 223143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 223243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 223343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 223443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mIsAudio? 0: 1); 223543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 223643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 223743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 223843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mTrackDurationUs / 1000); 223943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 224043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 224143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 224243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mNumSamples); 224343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 224486b7f47aa7482424cf8fd248f1315311919be3b0James Dong { 224586b7f47aa7482424cf8fd248f1315311919be3b0James Dong // The system delay time excluding the requested initial delay that 224686b7f47aa7482424cf8fd248f1315311919be3b0James Dong // is used to eliminate the recording sound. 224786b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 224886b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 224986b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 225086b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 225186b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t initialDelayUs = 225286b7f47aa7482424cf8fd248f1315311919be3b0James Dong mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 225386b7f47aa7482424cf8fd248f1315311919be3b0James Dong 225486b7f47aa7482424cf8fd248f1315311919be3b0James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 225570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 225670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong (initialDelayUs) / 1000); 225786b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 225870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 225943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (hasMultipleTracks) { 226043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 226143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 226243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs / 1000); 226370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 226470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 226570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (mStartTimestampUs != moovStartTimeUs) { 226670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 226770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 226870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 226970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong startTimeOffsetUs / 1000); 227070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 227143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 227243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong} 227343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 2274faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2275faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 2276215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 2277215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 227893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 2279bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 228093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 228193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 228293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 228393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 2284faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 2285bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong size_t trackId, int64_t timeUs, status_t err) { 2286faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 2287bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t trackNum = (trackId << 28); 2288faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2289faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 2290faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 2291faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 2292bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2293bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 2294faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2295faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2296faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2297faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2298faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 2299faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 2300bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2301bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 2302faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2303faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 2304faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 2305bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2306bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 2307faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 2308faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2309faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 2310faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2311d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2312d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong LOGV("setDriftTimeUs: %lld us", driftTimeUs); 2313e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2314d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 2315e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2316e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2317e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 2318e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 2319e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2320e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 2321e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2322e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2323b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() { 2324b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong return mUse4ByteNalLength; 2325b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong} 2326b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 23271c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 23281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 23291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 23301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 23311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 233213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 233320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 233420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 23353b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 2336c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 233720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 233820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2339d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2340d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 2341d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 2342d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2343690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 2344690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 2345690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2346690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2347690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2348690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2349690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 2350690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 2351a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Missing codec specific data"); 2352690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2353690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2354690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 2355690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 2356690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 2357a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Unexepected codec specific data found"); 2358690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2359690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2360690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2361690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 2362690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 2363690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2364b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 236520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 23668f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 23671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 23688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 236920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 2370b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("trak"); 2371b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeTkhdBox(now); 2372b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdia"); 2373b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMdhdBox(now); 2374b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeHdlrBox(); 2375b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("minf"); 2376b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2377b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSmhdBox(); 2378b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2379b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVmhdBox(); 2380b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2381b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDinfBox(); 2382b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStblBox(use32BitOffset); 2383b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // minf 2384b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mdia 2385b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // trak 2386b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2387b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2388b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 2389b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stbl"); 2390b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsd"); 2391b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2392b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count 2393b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2394b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAudioFourCCBox(); 2395b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2396b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVideoFourCCBox(); 2397b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2398b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsd 2399b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSttsBox(); 2400b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!mIsAudio) { 2401b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStssBox(); 2402b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2403b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStszBox(); 2404b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStscBox(); 2405b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStcoBox(use32BitOffset); 2406b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stbl 2407b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2408b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2409b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() { 2410b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2411b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2412b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2413b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2414b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mp4v"); 2415b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2416b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("s263"); 2417b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2418b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("avc1"); 2419b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2420b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong LOGE("Unknown mime type '%s'.", mime); 2421b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2422b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2423b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2424b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2425b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2426b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // data ref index 2427b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2428b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2429b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2430b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2431b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2432b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2433b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 2434b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeyWidth, &width); 2435b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 2436b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2437b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2438b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(width); 2439b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(height); 2440b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // horiz resolution 2441b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // vert resolution 2442b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2443b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // frame count 2444b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(" ", 32); 2445b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x18); // depth 2446b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(-1); // predefined 2447b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2448b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(23 + mCodecSpecificDataSize < 128); 2449b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2450b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2451b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4vEsdsBox(); 2452b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2453b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeD263Box(); 2454b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2455b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAvccBox(); 2456b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2457b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2458b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writePaspBox(); 2459b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mp4v, s263 or avc1 2460b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2461b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2462b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() { 2463b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2464b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2465b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2466b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *fourcc = NULL; 2467b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 2468b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "samr"; 2469b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2470b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "sawb"; 2471b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2472b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "mp4a"; 2473b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2474b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong LOGE("Unknown mime type '%s'.", mime); 2475b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2476b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2477b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2478b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(fourcc); // audio format 2479b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2480b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2481b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x1); // data ref index 2482b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2483b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2484b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t nChannels; 2485b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2486b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(nChannels); // channel count 2487b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(16); // sample size 2488b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2489b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2490b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2491b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t samplerate; 2492b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeySampleRate, &samplerate); 2493b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2494b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(samplerate << 16); 2495b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2496b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4aEsdsBox(); 2497b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 2498b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2499b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDamrBox(); 2500b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2501b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2502b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2503b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2504b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() { 2505b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 2506b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 2507b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize > 0); 2508b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2509b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Make sure all sizes encode to a single byte. 2510b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize + 23 < 128); 2511b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2512b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2513b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 2514b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2515b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000);// ES_ID 2516b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x00); 2517b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2518b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2519b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2520b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2521b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x15); // streamType AudioStream 2522b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2523b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x03); // XXX 2524b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2525b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(96000); // max bit rate 2526b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(96000); // avg bit rate 2527b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2528b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2529b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 2530b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2531b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2532b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 2533b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 2534b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 2535b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 2536b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2537b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 2538b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2539b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 2540b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2541b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2542b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() { 2543b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 2544b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize > 0); 2545b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 2546b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2547b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2548b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2549b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 2550b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2551b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000); // ES_ID 2552b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x1f); 2553b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2554b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2555b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2556b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 2557b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x11); // streamType VisualStream 2558b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2559b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData[] = { 2560b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 0x77, 0x00, 2561b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x00, 0x03, 0xe8, 0x00, 2562b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x00, 0x03, 0xe8, 0x00 2563b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2564b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData, sizeof(kData)); 2565b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2566b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2567b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2568b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 2569b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2570b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2571b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 2572b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 2573b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 2574b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 2575b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2576b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 2577b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2578b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 2579b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2580b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2581b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTkhdBox(time_t now) { 2582b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("tkhd"); 2583b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Flags = 7 to indicate that the track is enabled, and 2584b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // part of the presentation 2585b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x07); // version=0, flags=7 2586b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 2587b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 2588b5212db69734962f55e1493d3e696794172ced51James Dong mOwner->writeInt32(mTrackId + 1); // track id starts with 1 2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 25908f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 2591b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 2592b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t tkhdDuration = 2593b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 2594b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 2595b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2597b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // layer 2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // alternate group 2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCompositionMatrix(mRotation); // matrix 260320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2608b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findInt32(kKeyWidth, &width); 2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 2611b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // tkhd 2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() { 2620b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("vmhd"); 2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x01); // version=0, flags=1 2622b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // graphics mode 2623b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // opcolor 2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 2625b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2627b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() { 2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("smhd"); 2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2632b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // balance 2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() { 2638b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("hdlr"); 2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2640b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // component type: should be mhlr 2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Removing "r" for the name string just makes the string 4 byte aligned 2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMdhdBox(time_t now) { 2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t trakDurationUs = getDurationUs(); 2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdhd"); 2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2654b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 2656b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mTimeScale); // media timescale 2657b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mdhdDuration); // use media timescale 2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Language follows the three letter standard ISO-639-2/T 2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 'e', 'n', 'g' for "English", for instance. 2661b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Each character is packed as the difference between its ASCII value and 0x60. 2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // For "English", these are 00101, 01110, 00111. 2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // XXX: Where is the padding bit located: 0x15C7? 2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // language code 2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() { 2670b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 3gpp2 Spec AMRSampleEntry fields 2671b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("damr"); 2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(" "); // vendor: 4 bytes 2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 2675b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // mode change period 2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(1); // frames per sample 2677b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() { 2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // The table index here refers to the sample description index 2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // in the sample table entries. 2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("url "); 2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // url 2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2687b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() { 2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dref"); 2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count (either url or urn) 2692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeUrlBox(); 2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dref 2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() { 2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dinf"); 2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDrefBox(); 2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dinf 2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() { 2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize >= 5); 2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Patch avcc's lengthSize field to match the number 2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // of bytes we use to indicate the size of a nal unit. 2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong uint8_t *ptr = (uint8_t *)mCodecSpecificData; 2709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("avcC"); 2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // avcC 2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() { 2716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("d263"); 2717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // vendor 2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(10); // level: 10 2720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // profile: 0 2721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // d263 2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square 2725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() { 2726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("pasp"); 2727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // hspacing 2728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // vspacing 2729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // pasp 2730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSttsBox() { 2733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stts"); 2734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumSttsTableEntries); 273670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 2737a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Compensate for small start time difference from different media tracks 2738a472613aec322e25891abf5c77bf3f7e3c244920James Dong int64_t trackStartTimeOffsetUs = 0; 2739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 2740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mStartTimestampUs != moovStartTimeUs) { 2741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mStartTimestampUs > moovStartTimeUs); 2742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 2743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t prevTimestampUs = trackStartTimeOffsetUs; 2745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 2746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mSttsTableEntries.end(); ++it) { 2747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(it->sampleCount); 2748a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Make sure that we are calculating the sample duration the exactly 2750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // same way as we made decision on how to create stts entries. 2751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; 2752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - 2753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong prevTimestampUs += (it->sampleCount * it->sampleDurationUs); 275520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(dur); 2757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stts 2759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 276020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() { 2762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stss"); 2763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumStssTableEntries); // number of sync frames 2765b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2766b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mStssTableEntries.end(); ++it) { 2767b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(*it); 2768b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2769b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stss 2770b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 277125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 2772b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() { 2773b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsz"); 2774b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2775b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mSamplesHaveSameSize) { 2776b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong List<size_t>::iterator it = mSampleSizes.begin(); 2777b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(*it); // default sample size 2778b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2779b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2780b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2781b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumSamples); 2782b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!mSamplesHaveSameSize) { 2783b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 2784b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mSampleSizes.end(); ++it) { 2785b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(*it); 2786b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2787b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2788b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsz 2789b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 279020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2791b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() { 2792b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsc"); 2793b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2794b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumStscTableEntries); 2795b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 2796b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mStscTableEntries.end(); ++it) { 2797b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(it->firstChunk); 2798b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(it->samplesPerChunk); 2799b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(it->sampleDescriptionId); 2800b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2801b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsc 2802b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 280320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2804b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 2805b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 2806b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2807b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumStcoTableEntries); 2808b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<off64_t>::iterator it = mChunkOffsets.begin(); 2809b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mChunkOffsets.end(); ++it) { 2810b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (use32BitOffset) { 2811b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 2812b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2813b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt64((*it)); 2814b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2815b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2816b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stco or co64 281720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 281820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 281907b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() { 282007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("udta"); 282107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeGeoDataBox(); 282207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 282307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 282407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 282507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 282607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 282707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 282807b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() { 282907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("\xA9xyz"); 283007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong /* 283107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * For historical reasons, any user data start 283207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * with "\0xA9", must be followed by its assoicated 283307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * language code. 283407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * 0x0012: locale en 283507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * 0x15c7: language 5575 283607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 283707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt32(0x001215c7); 283807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLatitude(mLatitudex10000); 283907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLongitude(mLongitudex10000); 284007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt8(0x2F); 284107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 284207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 284307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 284420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2845