MPEG4Writer.cpp revision 79761ab096f57c3027fad9556c2bc436672d614e
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> 3607ec01904613a0bac32caaa8444b4690998faed7James Dong#include <cutils/properties.h> 37674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/types.h> 38674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/stat.h> 39674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <fcntl.h> 40674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <unistd.h> 4120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 4319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL; 473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 4970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongstatic const int64_t kInitialDelayTimeUs = 700000LL; 505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong 515b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// Using longer adjustment period to suppress fluctuations in 525b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// the audio encoding paths 535b6a01e65aa4129a9226667536d1bc1dad5980d8James Dongstatic const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL; // 10 minutes 543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 5620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 57bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); 588f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 5920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 6020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 6237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 6337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 6425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 6520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 663b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 67d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 68b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeTrackHeader(bool use32BitOffset = true); 691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 73c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong void addChunkOffset(off64_t offset); 7470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int32_t getTrackId() const { return mTrackId; } 75dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong status_t dump(int fd, const Vector<String16>& args) const; 7620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 7820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 7920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 80693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 8120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 82a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 83a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 84eaae38445a340c4857c1c5569475879a728e63b7James Dong volatile bool mStarted; 851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 88bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t mTrackId; 89c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 9043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t mMaxChunkDurationUs; 91e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 92e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // For realtime applications, we need to adjust the media clock 93e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // for video track based on the audio media clock 94e259531ce59ab1f31de5a23124b22536f6a5a767James Dong bool mIsRealTimeRecording; 95e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t mMaxTimeStampUs; 96d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t mMdatSizeBytes; 988f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 10020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 10120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 102ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // mNumSamples is used to track how many samples in mSampleSizes List. 103ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // This is to reduce the cost associated with mSampleSizes.size() call, 104ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // since it is O(n). Ideally, the fix should be in List class. 105ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong size_t mNumSamples; 1068644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t> mSampleSizes; 107be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 108be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 10913aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 1101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStcoTableEntries; 112c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong List<off64_t> mChunkOffsets; 11313aec890216948b0c364f8f92792129d0335f506James Dong 1141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStscTableEntries; 11513aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 11613aec890216948b0c364f8f92792129d0335f506James Dong 11713aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 11813aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 11913aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 12013aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 12113aec890216948b0c364f8f92792129d0335f506James Dong 12213aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 12313aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 12413aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 12513aec890216948b0c364f8f92792129d0335f506James Dong }; 12613aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 12720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1281f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStssTableEntries; 129050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 130050b28a593350047845a45a14cc5026221ac1620James Dong 1311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumSttsTableEntries; 132be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 133be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 13479761ab096f57c3027fad9556c2bc436672d614eJames Dong SttsTableEntry(uint32_t count, uint32_t duration) 13579761ab096f57c3027fad9556c2bc436672d614eJames Dong : sampleCount(count), sampleDuration(duration) {} 136be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 137be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 13879761ab096f57c3027fad9556c2bc436672d614eJames Dong uint32_t sampleDuration; // time scale based 139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 140be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 141be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 1463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 1483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 1523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 1533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 1543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 1553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 15720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 158548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 15993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 16020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 16125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1623c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 16370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mStartTimeRealUs; 16470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t mFirstSampleTimeRealUs; 16593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 16693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 16725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 168872a481558350634a3fd5cb67939de288af00ecbJames Dong // Has the media time adjustment for video started? 169872a481558350634a3fd5cb67939de288af00ecbJames Dong bool mIsMediaTimeAdjustmentOn; 170872a481558350634a3fd5cb67939de288af00ecbJames Dong // The time stamp when previous media time adjustment period starts 171872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustTimestampUs; 172872a481558350634a3fd5cb67939de288af00ecbJames Dong // Number of vidoe frames whose time stamp may be adjusted 173872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mMediaTimeAdjustNumFrames; 174872a481558350634a3fd5cb67939de288af00ecbJames Dong // The sample number when previous meida time adjustmnet period starts 175872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustSample; 176872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumulated drift time within a period of 177872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 178872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mTotalDriftTimeToAdjustUs; 179872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumalated drift time since the start of the recording 180872a481558350634a3fd5cb67939de288af00ecbJames Dong // excluding the current time adjustment period 181872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevTotalAccumDriftTimeUs; 182872a481558350634a3fd5cb67939de288af00ecbJames Dong 183872a481558350634a3fd5cb67939de288af00ecbJames Dong // Update the audio track's drift information. 184872a481558350634a3fd5cb67939de288af00ecbJames Dong void updateDriftTime(const sp<MetaData>& meta); 185872a481558350634a3fd5cb67939de288af00ecbJames Dong 186872a481558350634a3fd5cb67939de288af00ecbJames Dong // Adjust the time stamp of the video track according to 187872a481558350634a3fd5cb67939de288af00ecbJames Dong // the drift time information from the audio track. 188872a481558350634a3fd5cb67939de288af00ecbJames Dong void adjustMediaTime(int64_t *timestampUs); 189872a481558350634a3fd5cb67939de288af00ecbJames Dong 19020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 19137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 19220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 1943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 1953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 196b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size); 197b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size); 198b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size); 199215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 200215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 201faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 20293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 20303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 20419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 20519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 206c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 207c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 208c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 209c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 210c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 211c059860c73678a202bfa33062723e8f82fb779d9James Dong 212690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 213690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 21413f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t mRotation; 215690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void updateTrackSizeEstimate(); 2171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStscTableEntry(size_t chunkId, size_t sampleId); 2181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStssTableEntry(size_t sampleId); 21979761ab096f57c3027fad9556c2bc436672d614eJames Dong 22079761ab096f57c3027fad9556c2bc436672d614eJames Dong // Duration is time scale based 22179761ab096f57c3027fad9556c2bc436672d614eJames Dong void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur); 22243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong void sendTrackSummary(bool hasMultipleTracks); 2231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 224b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Write the boxes 225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStcoBox(bool use32BitOffset); 226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStscBox(); 227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStszBox(); 228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStssBox(); 229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSttsBox(); 230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeD263Box(); 231b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writePaspBox(); 232b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAvccBox(); 233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeUrlBox(); 234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDrefBox(); 235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDinfBox(); 236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeDamrBox(); 237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMdhdBox(time_t now); 238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeSmhdBox(); 239b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVmhdBox(); 240b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeHdlrBox(); 241b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeTkhdBox(time_t now); 242b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4aEsdsBox(); 243b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeMp4vEsdsBox(); 244b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeAudioFourCCBox(); 245b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeVideoFourCCBox(); 246b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong void writeStblBox(bool use32BitOffset); 247b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 24820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 24920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 25020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 25120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 25220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 253674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(-1), 254674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(NO_INIT), 255b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2561acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 257a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 258a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 259a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 26020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 26113aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2627837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 26307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mInterleaveDurationUs(1000000), 26407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000(0), 26507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000(0), 26686b7f47aa7482424cf8fd248f1315311919be3b0James Dong mAreGeoTagsAvailable(false), 26786b7f47aa7482424cf8fd248f1315311919be3b0James Dong mStartTimeOffsetMs(-1) { 268674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong 26903f6f4e7e2ce09357cbc05bb546cd8a6e54b5baeJames Dong mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR); 270674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mFd >= 0) { 271674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = OK; 272674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong } 27320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 27420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 27530ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 276674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(dup(fd)), 277674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(mFd < 0? NO_INIT: OK), 278b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 280a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 281a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 282a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 28330ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 28413aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2857837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 28607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mInterleaveDurationUs(1000000), 28707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000(0), 28807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000(0), 28986b7f47aa7482424cf8fd248f1315311919be3b0James Dong mAreGeoTagsAvailable(false), 29086b7f47aa7482424cf8fd248f1315311919be3b0James Dong mStartTimeOffsetMs(-1) { 29130ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 29230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 29320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 29420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 29520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong while (!mTracks.empty()) { 2971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong List<Track *>::iterator it = mTracks.begin(); 29820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 2991f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong (*it) = NULL; 3001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mTracks.erase(it); 30120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 30220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 30320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 30420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 305dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 306dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 307dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 308dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 309dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 310dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 311dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 312dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 313dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 314dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 315dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 316dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 317dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 318dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 319dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 320dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 321dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 322dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 323dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) const { 324dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 325dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 326dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 327dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 328dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 329dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 330dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 331dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 332dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 333dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 334dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 335dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 3362dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 337bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Mutex::Autolock l(mLock); 338bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong if (mStarted) { 339bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong LOGE("Attempt to add source AFTER recording is started"); 340bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong return UNKNOWN_ERROR; 341bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong } 342bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Track *track = new Track(this, source, mTracks.size()); 34320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 3442dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 3452dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 34620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 34720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 34893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 349a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 350a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 35193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 352a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 353a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 354a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 355a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 356a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 357a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 358a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 359a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 360a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 361a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 362a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 363a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 364a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3652dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 3662dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 3672dec2b5be2056c6d9428897dc672185872d30d17James Dong // 3682dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 3692dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 3702dec2b5be2056c6d9428897dc672185872d30d17James Dong 37178a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 3722dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 37378a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 3 3742dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 3752dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 3762dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 3772dec2b5be2056c6d9428897dc672185872d30d17James Dong 3782dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 3792dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 3802dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 38178a1a286f736888ae7af8860b2c424af0d978848James Dong static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 3822dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 3832dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 3842dec2b5be2056c6d9428897dc672185872d30d17James Dong 38578a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file size limit is set 386a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 38778a1a286f736888ae7af8860b2c424af0d978848James Dong size = mMaxFileSizeLimitBytes * 6 / 1000; 38878a1a286f736888ae7af8860b2c424af0d978848James Dong } 38978a1a286f736888ae7af8860b2c424af0d978848James Dong 39078a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file duration limit is set 39178a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileDurationLimitUs != 0) { 39278a1a286f736888ae7af8860b2c424af0d978848James Dong if (bitRate > 0) { 39378a1a286f736888ae7af8860b2c424af0d978848James Dong int64_t size2 = 39478a1a286f736888ae7af8860b2c424af0d978848James Dong ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 39578a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 39678a1a286f736888ae7af8860b2c424af0d978848James Dong // When both file size and duration limits are set, 39778a1a286f736888ae7af8860b2c424af0d978848James Dong // we use the smaller limit of the two. 39878a1a286f736888ae7af8860b2c424af0d978848James Dong if (size > size2) { 39978a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 40078a1a286f736888ae7af8860b2c424af0d978848James Dong } 40178a1a286f736888ae7af8860b2c424af0d978848James Dong } else { 40278a1a286f736888ae7af8860b2c424af0d978848James Dong // Only max file duration limit is set 40378a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 40478a1a286f736888ae7af8860b2c424af0d978848James Dong } 4052dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4062dec2b5be2056c6d9428897dc672185872d30d17James Dong } 40778a1a286f736888ae7af8860b2c424af0d978848James Dong 4082dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 4092dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 4102dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4112dec2b5be2056c6d9428897dc672185872d30d17James Dong 4122dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 4132dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 4142dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 4152dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 4162dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4172dec2b5be2056c6d9428897dc672185872d30d17James Dong 418a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 4192dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 4202dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 4212dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 4222dec2b5be2056c6d9428897dc672185872d30d17James Dong} 4232dec2b5be2056c6d9428897dc672185872d30d17James Dong 4242dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 425674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 42625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 42720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 42820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 429a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong /* 430a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * Check mMaxFileSizeLimitBytes at the beginning 431a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * since mMaxFileSizeLimitBytes may be implicitly 432a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * changed later for 32-bit file offset even if 433a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * user does not ask to set it explicitly. 434a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong */ 435a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0) { 436a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested = true; 437a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong } 438a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong 4392dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 4402dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 4412dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 4422dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 4432dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 4442dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4452dec2b5be2056c6d9428897dc672185872d30d17James Dong 4461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mUse32BitOffset) { 4471f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // Implicit 32 bit file size limit 4481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes == 0) { 4491f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 4521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // If file size is set to be larger than the 32 bit file 4531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // size limit, treat it as an error. 4541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 455872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGW("32-bit file size limit (%lld bytes) too big. " 456d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong "It is changed to %lld bytes", 457d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes, kMax32BitFileSize); 458d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 462b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong int32_t use2ByteNalLength; 463b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (param && 464b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 465b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong use2ByteNalLength) { 466b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength = false; 4672dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4682dec2b5be2056c6d9428897dc672185872d30d17James Dong 469065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 47093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 471a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 472a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 473a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 47493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 475a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 476a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 477a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 478a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 4798f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 4808f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 4818f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 4828f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 4838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 4848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 4858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 4867837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 4877837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 4887837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 4897837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4907837c17063a4c50bc856ba59418516fdab731de7James Dong 491b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFtypBox(param); 49220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4937837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 49420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4957837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 4962dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 4972dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 4982dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 4992dec2b5be2056c6d9428897dc672185872d30d17James Dong } 5002dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 5017837c17063a4c50bc856ba59418516fdab731de7James Dong } 5027837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 503c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 5047837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 5057837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 5067837c17063a4c50bc856ba59418516fdab731de7James Dong 5077837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 5087837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 509c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 5101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 5111acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 5121acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 5131acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 5141acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 5151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 5171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 5181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 5191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 5201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 522a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 523a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 52420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 5251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 526a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 52725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const { 5311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong return mUse32BitOffset; 5321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 5331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 53437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 535674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 53637187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 537a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 538a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 53937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 540a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 541a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 54237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 54337187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 54437187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 54537187916a486504acaf83bea30147eb5fbf46ae5James Dong } 546a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 54737187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 548a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 549a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 5501c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 551cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping writer thread"); 5521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 5541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 5551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 5571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 5581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 5591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 5611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 562cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Writer thread stopped"); 5631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 5641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 56513f6284305e4b27395a23db7882d670bdb1bcae1James Dong/* 56613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix: 56713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a b u | 56813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c d v | 56913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x y w | 57013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * 57113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following 57213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w}, 57313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while 57413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format. 57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong */ 57613f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) { 57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong LOGV("writeCompositionMatrix"); 57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t a = 0x00010000; 57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t b = 0; 58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t c = 0; 58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t d = 0x00010000; 58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong switch (degrees) { 58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 0: 58413f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 58513f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 90: 58613f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 58713f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0x00010000; 58813f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0xFFFF0000; 58913f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 59013f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 59113f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 180: 59213f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0xFFFF0000; 59313f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0xFFFF0000; 59413f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 59513f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 270: 59613f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 59713f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0xFFFF0000; 59813f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0x00010000; 59913f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 60013f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 60113f6284305e4b27395a23db7882d670bdb1bcae1James Dong default: 60213f6284305e4b27395a23db7882d670bdb1bcae1James Dong CHECK(!"Should never reach this unknown rotation"); 60313f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 60413f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 60513f6284305e4b27395a23db7882d670bdb1bcae1James Dong 60613f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(a); // a 60713f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(b); // b 60813f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // u 60913f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(c); // c 61013f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(d); // d 61113f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // v 61213f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // x 61313f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // y 61413f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0x40000000); // w 61513f6284305e4b27395a23db7882d670bdb1bcae1James Dong} 61613f6284305e4b27395a23db7882d670bdb1bcae1James Dong 61713f6284305e4b27395a23db7882d670bdb1bcae1James Dong 61837187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() { 619674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 62037187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 62120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 62220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 62337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 6248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 62565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong int64_t minDurationUs = 0x7fffffffffffffffLL; 62620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 62720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 62837187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 62937187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 63037187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 63137187916a486504acaf83bea30147eb5fbf46ae5James Dong } 63220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 6348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 6358f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 63620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 63765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (durationUs < minDurationUs) { 63865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs = durationUs; 63965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 64065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 64165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong 64265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (mTracks.size() > 1) { 64365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong LOGD("Duration from tracks range is [%lld, %lld] us", 64465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs, maxDurationUs); 64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 6487837c17063a4c50bc856ba59418516fdab731de7James Dong 64937187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 65037187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 651674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 652674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 653674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 65437187916a486504acaf83bea30147eb5fbf46ae5James Dong mStarted = false; 65537187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 65637187916a486504acaf83bea30147eb5fbf46ae5James Dong } 65737187916a486504acaf83bea30147eb5fbf46ae5James Dong 65820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 6591acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 660c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 6611acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 662c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 4); 6631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 664c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset + 8, SEEK_SET); 6651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 6661acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 667c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 8); 6681acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 669c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 67020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 671c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong const off64_t moovOffset = mOffset; 6727837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 6737837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 6747837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6757837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMoovBox(maxDurationUs); 67720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6787837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6797837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 6807837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 6817837c17063a4c50bc856ba59418516fdab731de7James Dong 6827837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 683c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 6847837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 685674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 6867837c17063a4c50bc856ba59418516fdab731de7James Dong 6877837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 688c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 6897837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 6907837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 6917837c17063a4c50bc856ba59418516fdab731de7James Dong 6927837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 6937837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 6947837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6957837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6962dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 6972dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 6987837c17063a4c50bc856ba59418516fdab731de7James Dong } 6997837c17063a4c50bc856ba59418516fdab731de7James Dong 7000c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 70120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 702674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 703674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 704674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 705a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 70670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 70737187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 70920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) { 711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong time_t now = time(NULL); 712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("mvhd"); 713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // version=0, flags=0 714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // creation time 715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(now); // modification time 716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTimeScale); // mvhd timescale 717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; 718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(duration); 719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0x10000); // rate: 1.0 720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0x100); // volume 721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt16(0); // reserved 722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // reserved 724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeCompositionMatrix(0); // matrix 725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); // predefined 731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(mTracks.size() + 1); // nextTrackID 732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // mvhd 733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) { 736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("moov"); 737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMvhdBox(durationUs); 73807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (mAreGeoTagsAvailable) { 73907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeUdtaBox(); 74007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t id = 1; 742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<Track *>::iterator it = mTracks.begin(); 743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mTracks.end(); ++it, ++id) { 744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (*it)->writeTrackHeader(mUse32BitOffset); 745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); // moov 747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 7492cf9c5073ca3342ee52673ad68763fadd2c2be79James Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) { 750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong beginBox("ftyp"); 751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t fileType; 753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (param && param->findInt32(kKeyFileType, &fileType) && 754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fileType != OUTPUT_FORMAT_MPEG_4) { 755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("3gp4"); 756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("isom"); 758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeInt32(0); 761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("isom"); 762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeFourcc("3gp4"); 763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong endBox(); 764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 765b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 76607ec01904613a0bac32caaa8444b4690998faed7James Dongstatic bool isTestModeEnabled() { 76707ec01904613a0bac32caaa8444b4690998faed7James Dong#if (PROPERTY_VALUE_MAX < 5) 76807ec01904613a0bac32caaa8444b4690998faed7James Dong#error "PROPERTY_VALUE_MAX must be at least 5" 76907ec01904613a0bac32caaa8444b4690998faed7James Dong#endif 77007ec01904613a0bac32caaa8444b4690998faed7James Dong 77107ec01904613a0bac32caaa8444b4690998faed7James Dong // Test mode is enabled only if rw.media.record.test system 77207ec01904613a0bac32caaa8444b4690998faed7James Dong // property is enabled. 77307ec01904613a0bac32caaa8444b4690998faed7James Dong char value[PROPERTY_VALUE_MAX]; 77407ec01904613a0bac32caaa8444b4690998faed7James Dong if (property_get("rw.media.record.test", value, NULL) && 77507ec01904613a0bac32caaa8444b4690998faed7James Dong (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) { 77607ec01904613a0bac32caaa8444b4690998faed7James Dong return true; 77707ec01904613a0bac32caaa8444b4690998faed7James Dong } 77807ec01904613a0bac32caaa8444b4690998faed7James Dong return false; 77907ec01904613a0bac32caaa8444b4690998faed7James Dong} 78007ec01904613a0bac32caaa8444b4690998faed7James Dong 78170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() { 78207ec01904613a0bac32caaa8444b4690998faed7James Dong // Send session summary only if test mode is enabled 78307ec01904613a0bac32caaa8444b4690998faed7James Dong if (!isTestModeEnabled()) { 78407ec01904613a0bac32caaa8444b4690998faed7James Dong return; 78507ec01904613a0bac32caaa8444b4690998faed7James Dong } 78607ec01904613a0bac32caaa8444b4690998faed7James Dong 78770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 78870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it != mChunkInfos.end(); ++it) { 78970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int trackNum = it->mTrack->getTrackId() << 28; 79070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 79170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, 79270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs); 79370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 79470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong} 79570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 79613aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 79713aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 79813aec890216948b0c364f8f92792129d0335f506James Dong return OK; 79913aec890216948b0c364f8f92792129d0335f506James Dong} 80013aec890216948b0c364f8f92792129d0335f506James Dong 80113aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 80213aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 80313aec890216948b0c364f8f92792129d0335f506James Dong} 80413aec890216948b0c364f8f92792129d0335f506James Dong 80513aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 80613aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 80713aec890216948b0c364f8f92792129d0335f506James Dong} 80820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 809c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 810c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 81120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 812c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 813c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 814c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong buffer->range_length()); 81520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 81620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 81720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 81820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 81920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 82020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 82203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 82303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 82403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 82503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 82603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 82703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 82803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 82903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 83003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 83103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 83203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 83303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 83403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 835c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 836c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 83730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 83830ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 83903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 840b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mUse4ByteNalLength) { 841b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 24; 842c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 843b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 16) & 0xff; 844c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 845b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 8) & 0xff; 846c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 847b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 848c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 849c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong 850c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 851c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 852c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong length); 853b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 854b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 4; 855b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 856b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong CHECK(length < 65536); 85730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 858b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 8; 859c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 860b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 861c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 862c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 863b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 2; 864b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 86530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 86630ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 86730ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 86830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 8697837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 870674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong const void *ptr, size_t size, size_t nmemb) { 8717837c17063a4c50bc856ba59418516fdab731de7James Dong 8727837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 8737837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 874674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // This happens only when we write the moov box at the end of 875674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // recording, not for each output video/audio frame we receive. 876c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 8771acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 878c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mBoxes.begin(); 8797837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 8807837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 8817837c17063a4c50bc856ba59418516fdab731de7James Dong } 882674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong lseek64(mFd, mOffset, SEEK_SET); 883674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 884674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 8857837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 8867837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 8877837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 8887837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 8897837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 8907837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 8917837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 8927837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 8937837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 8947837c17063a4c50bc856ba59418516fdab731de7James Dong } 8957837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 896674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 8977837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 8987837c17063a4c50bc856ba59418516fdab731de7James Dong } 8997837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 9007837c17063a4c50bc856ba59418516fdab731de7James Dong} 9017837c17063a4c50bc856ba59418516fdab731de7James Dong 90220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 9030c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 90420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9057837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 9067837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 90720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 90820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 91120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 91220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 9130c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 91420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 915c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = *--mBoxes.end(); 91620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 91720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9187837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 9197837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 9207837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 9217837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 922c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, offset, SEEK_SET); 9237837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 9247837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 925c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 9267837c17063a4c50bc856ba59418516fdab731de7James Dong } 92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 92820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 930674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 1); 93120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 93220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 93320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 93420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 935674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 2); 93620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 93720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 93820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 93920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 940674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 4); 94120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 94220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 94320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 94420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 945674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 8); 94620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 94720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 94820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 94920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 950674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, n + 1); 95120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 95220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 95320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 9540c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 955674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, 4); 95620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 95720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 95807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 95907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format 96007b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) { 96107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 96207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 96307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 96407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 96507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[9]; 96607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 96707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 96807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%c%.2d.", sign, wholePart); 96907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 97007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 5, "%+.2d.", wholePart); 97107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 97207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 97307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 97407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 97507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 97607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 97707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 97807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[4], 5, "%.4d", fractionalPart); 97907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 98007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 98107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 8); 98207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 98307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 98407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format 98507b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) { 98607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong bool isNegative = (degreex10000 < 0); 98707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char sign = isNegative? '-': '+'; 98807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 98907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the whole part 99007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong char str[10]; 99107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int wholePart = degreex10000 / 10000; 99207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (wholePart == 0) { 99307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%c%.3d.", sign, wholePart); 99407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } else { 99507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(str, 6, "%+.3d.", wholePart); 99607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 99707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 99807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Handle the fractional part 99907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong int fractionalPart = degreex10000 - (wholePart * 10000); 100007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (fractionalPart < 0) { 100107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong fractionalPart = -fractionalPart; 100207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 100307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong snprintf(&str[5], 5, "%.4d", fractionalPart); 100407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 100507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Do not write the null terminator 100607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong write(str, 1, 9); 100707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 100807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 100907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 101007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 101107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and 101207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000. 101307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and 101407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180] 101507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 101607b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { 101707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong // Is latitude or longitude out of range? 101807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong if (latitudex10000 < -900000 || latitudex10000 > 900000 || 101907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong longitudex10000 < -1800000 || longitudex10000 > 1800000) { 102007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return BAD_VALUE; 102107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong } 102207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 102307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLatitudex10000 = latitudex10000; 102407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mLongitudex10000 = longitudex10000; 102507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong mAreGeoTagsAvailable = true; 102607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong return OK; 102707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 102807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 102920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 1030674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(data, 1, size); 103120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 103220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 103378a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const { 103478a1a286f736888ae7af8860b2c424af0d978848James Dong return mStreamableFile; 103578a1a286f736888ae7af8860b2c424af0d978848James Dong} 103678a1a286f736888ae7af8860b2c424af0d978848James Dong 1037d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 1038d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1039d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 1040d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1041d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1042d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1043956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 1044d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1045d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1046d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1047d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 10481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1049acd234bba9f048971d66890009eeff9a8db94be3James Dong // Be conservative in the estimate: do not exceed 95% of 1050acd234bba9f048971d66890009eeff9a8db94be3James Dong // the target file limit. For small target file size limit, though, 1051acd234bba9f048971d66890009eeff9a8db94be3James Dong // this will not help. 1052acd234bba9f048971d66890009eeff9a8db94be3James Dong return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 1053d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1054d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1055d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 1056d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 1057d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 1058d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1059d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1060d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1061d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 1062d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 1063d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 1064d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 1065d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1066d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1067d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 1068d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1069d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 107025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 107125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 107225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 107325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 107425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 107525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 107625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 107725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 107825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 107925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 108025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 108125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 108225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 1083f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 1084f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 1085f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 10863c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 1087065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 1088f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 1089f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 10903c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 10913c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 10923c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 1093f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 10943c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 10953c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 10963c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 10973c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 109858ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 109958ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 110058ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 110158ae9c530247668f8af36e30d228c716c226b3d4James Dong} 110258ae9c530247668f8af36e30d228c716c226b3d4James Dong 110320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 110420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 110520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 1106bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) 110720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 110825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 110920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 111020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 1111a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 1112a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 1113eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted(false), 1114bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mTrackId(trackId), 1115c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 1116956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 1117be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 111820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 111925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 1120548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 112113f6284305e4b27395a23db7882d670bdb1bcae1James Dong mReachedEOS(false), 112213f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation(0) { 112319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 11248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 11251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 11261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 11271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 11281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 11291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 11301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 11311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1132c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 1133c059860c73678a202bfa33062723e8f82fb779d9James Dong} 1134c059860c73678a202bfa33062723e8f82fb779d9James Dong 11351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() { 11361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset() 11381f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ? mNumStcoTableEntries * 4 11391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong : mNumStcoTableEntries * 8; 11401f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11411f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4); 11421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 114378a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 114478a1a286f736888ae7af8860b2c424af0d978848James Dong if (!mOwner->isFileStreamable()) { 114578a1a286f736888ae7af8860b2c424af0d978848James Dong // Reserved free space is not large enough to hold 114678a1a286f736888ae7af8860b2c424af0d978848James Dong // all meta data and thus wasted. 114778a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 + // stsc box size 114878a1a286f736888ae7af8860b2c424af0d978848James Dong mNumStssTableEntries * 4 + // stss box size 114978a1a286f736888ae7af8860b2c424af0d978848James Dong mNumSttsTableEntries * 8 + // stts box size 115078a1a286f736888ae7af8860b2c424af0d978848James Dong stcoBoxSizeBytes + // stco box size 115178a1a286f736888ae7af8860b2c424af0d978848James Dong stszBoxSizeBytes; // stsz box size 115278a1a286f736888ae7af8860b2c424af0d978848James Dong } 11531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry( 11561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t chunkId, size_t sampleId) { 11571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong StscTableEntry stscEntry(chunkId, sampleId, 1); 11591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStscTableEntries.push_back(stscEntry); 11601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStscTableEntries; 11611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 11641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStssTableEntries.push_back(sampleId); 11651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStssTableEntries; 11661f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11671f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 11681f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry( 116979761ab096f57c3027fad9556c2bc436672d614eJames Dong size_t sampleCount, int32_t duration) { 11701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 117179761ab096f57c3027fad9556c2bc436672d614eJames Dong SttsTableEntry sttsEntry(sampleCount, duration); 11721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mSttsTableEntries.push_back(sttsEntry); 11731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumSttsTableEntries; 11741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1176c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) { 11771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStcoTableEntries; 11781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mChunkOffsets.push_back(offset); 11791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 11801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1181c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 1182c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 1183c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 1184c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 1185c059860c73678a202bfa33062723e8f82fb779d9James Dong 1186c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 1187c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 1188c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 1189c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1190c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 1191c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 1192c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1193c059860c73678a202bfa33062723e8f82fb779d9James Dong 1194c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 1195c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 1196c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1197c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 1198c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1199c059860c73678a202bfa33062723e8f82fb779d9James Dong 12008f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 120119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 120219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 120319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 120419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 120519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 120619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 120719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 120819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 120919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 121019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 121119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 121219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 121319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 121419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 121519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 121619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 121719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 121819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 121919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 122019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 122119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 122219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 122319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 122419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 122519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 122619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 122719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 122819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 122919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 123019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 123119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 123220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 123320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 123420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 123520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 123620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 123720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 123820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 123920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 124020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 124120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 124220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 124393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 124493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 124593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 124693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 124793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 124893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 124993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 125093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 125193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 125293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 125393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 125493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 125593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 125693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 125793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 12581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 12591c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 12601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 12611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 12621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 12631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 12641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12661c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 12671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 12681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 12691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 12701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 12721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 12731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 12751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 12761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 12771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 12781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 12821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1284fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) { 1285fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("writeChunkToFile: %lld from %s track", 1286fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video"); 1287fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1288fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong int32_t isFirstSample = true; 1289fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!chunk->mSamples.empty()) { 1290fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 1291fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1292fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong off64_t offset = chunk->mTrack->isAvc() 1293fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong ? addLengthPrefixedSample_l(*it) 1294fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong : addSample_l(*it); 1295fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1296fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (isFirstSample) { 1297fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mTrack->addChunkOffset(offset); 1298fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong isFirstSample = false; 12991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 13021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 1303fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.erase(it); 13041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1305fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.clear(); 13061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 13071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1308fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() { 1309fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("writeAllChunks"); 13101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 131170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong Chunk chunk; 131270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong while (findChunkToWrite(&chunk)) { 1313e9f6d0579603372fd2547e6c5ba6e114c6f8cba7James Dong writeChunkToFile(&chunk); 131470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong ++outstandingChunks; 13151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 131670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 131770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong sendSessionSummary(); 131870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 13191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 13201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 13211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 13221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1323fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 1324fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("findChunkToWrite"); 13251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 13271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 13281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 13291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 13301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 13311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 13321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 13331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 13341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 13351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 13401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 1341fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 13421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 13451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 13461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1347fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 13481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 13491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 13501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 1351fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong *chunk = *(it->mChunks.begin()); 1352fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong it->mChunks.erase(it->mChunks.begin()); 1353fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong CHECK_EQ(chunk->mTrack, track); 135470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 135570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t interChunkTimeUs = 135670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 135770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 135870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong it->mMaxInterChunkDurUs = interChunkTimeUs; 135970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 136070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 1361fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return true; 13621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1364fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1365fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 13661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 13671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13681c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 13691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 13701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1371a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 1372fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1373fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Mutex::Autolock autoLock(mLock); 13741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 1375fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Chunk chunk; 1376fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong bool chunkFound = false; 1377fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1378fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 13791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 13801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 13811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1382fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong // Actual write without holding the lock in order to 1383fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong // reduce the blocking time for media track threads. 1384fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (chunkFound) { 1385fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong mLock.unlock(); 1386fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeChunkToFile(&chunk); 1387fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong mLock.lock(); 1388fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong } 13891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1390fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1391fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeAllChunks(); 13921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 13931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13941c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 13951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 13961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 13971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 13981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1399e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 14001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 14011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 14021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 14031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 140470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mPrevChunkTimestampUs = 0; 140570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong info.mMaxInterChunkDurUs = 0; 14061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 14071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 14081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 14091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 14101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 14111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 14121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 14131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 14141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 14151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 14161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 14171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 141893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1419a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1420a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1421a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1422a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1423a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 142425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 142593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 142619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 142719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 142819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 142970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mStartTimeRealUs = startTimeUs; 143019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 143113f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t rotationDegrees; 143213f6284305e4b27395a23db7882d670bdb1bcae1James Dong if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 143313f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation = rotationDegrees; 143413f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 143513f6284305e4b27395a23db7882d670bdb1bcae1James Dong 14365b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong mIsRealTimeRecording = true; 1437e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1438e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1439e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1440e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1441e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1442e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1443e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 144493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 144593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1446f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1447a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mIsRealTimeRecording && mOwner->numTracks() > 1) { 1448a472613aec322e25891abf5c77bf3f7e3c244920James Dong /* 1449a472613aec322e25891abf5c77bf3f7e3c244920James Dong * This extra delay of accepting incoming audio/video signals 1450a472613aec322e25891abf5c77bf3f7e3c244920James Dong * helps to align a/v start time at the beginning of a recording 1451a472613aec322e25891abf5c77bf3f7e3c244920James Dong * session, and it also helps eliminate the "recording" sound for 1452a472613aec322e25891abf5c77bf3f7e3c244920James Dong * camcorder applications. 1453a472613aec322e25891abf5c77bf3f7e3c244920James Dong * 145486b7f47aa7482424cf8fd248f1315311919be3b0James Dong * If client does not set the start time offset, we fall back to 145586b7f47aa7482424cf8fd248f1315311919be3b0James Dong * use the default initial delay value. 1456a472613aec322e25891abf5c77bf3f7e3c244920James Dong */ 145786b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 145886b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 145986b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 146086b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 146186b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeUs += startTimeOffsetUs; 146286b7f47aa7482424cf8fd248f1315311919be3b0James Dong LOGI("Start time offset: %lld us", startTimeOffsetUs); 1463a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 1464a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1465f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1466a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1467f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 146825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 146925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 147025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 147125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 147220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 147320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 147420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 147520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 147620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 147720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1478eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted = true; 1479c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 148025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1481956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 14821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStcoTableEntries = 0; 14831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStssTableEntries = 0; 14841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStscTableEntries = 0; 14851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumSttsTableEntries = 0; 14861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes = 0; 1487872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = false; 1488872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = 0; 1489872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 0; 1490872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = 0; 1491872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 0; 1492872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = 0; 149343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = 0; 149420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 149525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 149620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 149725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 149825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 149920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 150020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 150137187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1502a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 150337187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1504a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1505a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 150637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 1507cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track", mIsAudio? "Audio": "Video"); 1508eaae38445a340c4857c1c5569475879a728e63b7James Dong if (!mStarted) { 1509eaae38445a340c4857c1c5569475879a728e63b7James Dong LOGE("Stop() called but track is not started"); 1510eaae38445a340c4857c1c5569475879a728e63b7James Dong return ERROR_END_OF_STREAM; 1511eaae38445a340c4857c1c5569475879a728e63b7James Dong } 1512eaae38445a340c4857c1c5569475879a728e63b7James Dong 151320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 151437187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 151520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 151620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 151720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 151820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 151920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 152020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 152137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = (status_t) dummy; 152237187916a486504acaf83bea30147eb5fbf46ae5James Dong 1523cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track source", mIsAudio? "Audio": "Video"); 152437187916a486504acaf83bea30147eb5fbf46ae5James Dong { 152537187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = mSource->stop(); 152637187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { 152737187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 152837187916a486504acaf83bea30147eb5fbf46ae5James Dong } 152937187916a486504acaf83bea30147eb5fbf46ae5James Dong } 153037187916a486504acaf83bea30147eb5fbf46ae5James Dong 1531cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("%s track stopped", mIsAudio? "Audio": "Video"); 153237187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 153320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 153420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 153525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 153625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 153725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 153825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 153920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 154020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 154120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 154220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 154337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 154437187916a486504acaf83bea30147eb5fbf46ae5James Dong return (void *) err; 154520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 154620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 15533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 15553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 15563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 15583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 15603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 15613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 15623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 15633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 15653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 15663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 15683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 15693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 15713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 15723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 15743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 15753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 15763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 15783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 15793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 15803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 15813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 15823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 15853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 15863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 15873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 15883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 15893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 15913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 15923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 15933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 15943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 15953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 15963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 15973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 15983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 15993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 16003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 16033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 16043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 16053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 16073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 16083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 16103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 16113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 16123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 16143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 16153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 16163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 16173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 16213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 16223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 16233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 16243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 16253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 16273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 16283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 16303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 16313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 16323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 16333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 16343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 16353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 16363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 16373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 16383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 16393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 16403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 16413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 16423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 16433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 16443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 16453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 16463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 16493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 16503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 16523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 16533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 16543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 16553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 16583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 16593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 16613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 16623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 16633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 16673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 16713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 16723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 16733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 16743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 16773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 16783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 16793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 16803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 16813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 16853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 16863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 16913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 16923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 16933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 16943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 16953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 16963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 16983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 16993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 17003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 17013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 17023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 17043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 17053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 17063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 17073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 17083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 17093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 17103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 17113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 17123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 17143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1715548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 171603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 171703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1718548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 171903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1720548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 172103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 172203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 172303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 17253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 172603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 172703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 172803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 17303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 17313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 173203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 173303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 173503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 173603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 173703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 17393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 174003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 174103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 17423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 17433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 17443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 17453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 174603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 1748b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1749b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 3; // length size == 4 bytes 1750b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1751b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 1; // length size == 2 bytes 1752b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 175303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 17543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 17553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 17563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 17573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 17583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 17593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 17603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 17613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 17623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 17633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 17643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 17663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 17673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 17683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 17693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 17713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 17723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 17733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 17743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 17753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 17763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 17773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 17783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 17793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 17803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 17813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 17823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 17833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 17843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 178503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 178603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 178703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 178803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1789872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1790872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications 1791872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows: 1792872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1793872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of 1794872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs 1795872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of 1796872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small 1797872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value 1798872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding 1799872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep 1800872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the 1801872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is 1802872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track. 1803872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1804872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found 1805872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed 1806872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames 1807872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames 1808872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period. 1809872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion 1810872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames 1811872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is 1812872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media 1813872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a 1814872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5). 1815872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1816872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that 1817872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift. 1818872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time 1819872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold 1820872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs. 1821872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental 1822872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the 1823872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift. 1824872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio 1825872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of 1826872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold 1827872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of 1828872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio 1829872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time 1830872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no 1831872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time 1832872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some 1833872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want 1834872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being. 1835872a481558350634a3fd5cb67939de288af00ecbJames Dong*/ 1836872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) { 1837872a481558350634a3fd5cb67939de288af00ecbJames Dong if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >= 1838872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs) { 1839872a481558350634a3fd5cb67939de288af00ecbJames Dong 1840872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("New media time adjustment period at %lld us", *timestampUs); 1841872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = true; 1842872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 1843872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample) >> 1; 1844872a481558350634a3fd5cb67939de288af00ecbJames Dong 1845872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = *timestampUs; 1846872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = mNumSamples; 1847872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs(); 1848872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 1849872a481558350634a3fd5cb67939de288af00ecbJames Dong totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs; 1850872a481558350634a3fd5cb67939de288af00ecbJames Dong 1851872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs; 1852872a481558350634a3fd5cb67939de288af00ecbJames Dong 1853872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on incremental adjusted time per frame 1854872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t adjustTimePerFrameUs = 1855872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames; 1856872a481558350634a3fd5cb67939de288af00ecbJames Dong 1857872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs < 0) { 1858872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs = -adjustTimePerFrameUs; 1859872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1860872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs >= 5000) { 1861872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Adjusted time per video frame is %lld us", 1862872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs); 1863872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"Video frame time adjustment is too large!"); 1864872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1865872a481558350634a3fd5cb67939de288af00ecbJames Dong 1866872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on total accumulated time drift within a period of 1867872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 1868872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000) 1869872a481558350634a3fd5cb67939de288af00ecbJames Dong / kVideoMediaTimeAdjustPeriodTimeUs; 1870872a481558350634a3fd5cb67939de288af00ecbJames Dong 1871872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage < 0) { 1872872a481558350634a3fd5cb67939de288af00ecbJames Dong driftPercentage = -driftPercentage; 1873872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1874872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage > 5) { 1875872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Audio track has time drift %lld us over %lld us", 1876872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs, 1877872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs); 1878872a481558350634a3fd5cb67939de288af00ecbJames Dong 1879872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"The audio track media time drifts too much!"); 1880872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1881872a481558350634a3fd5cb67939de288af00ecbJames Dong 1882872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1883872a481558350634a3fd5cb67939de288af00ecbJames Dong 1884872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsMediaTimeAdjustmentOn) { 1885872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mNumSamples - mPrevMediaTimeAdjustSample <= 1886872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames) { 1887872a481558350634a3fd5cb67939de288af00ecbJames Dong 1888872a481558350634a3fd5cb67939de288af00ecbJames Dong // Do media time incremental adjustment 1889872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t incrementalAdjustTimeUs = 1890872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs * 1891872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample)) 1892872a481558350634a3fd5cb67939de288af00ecbJames Dong / mMediaTimeAdjustNumFrames; 1893872a481558350634a3fd5cb67939de288af00ecbJames Dong 1894872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1895872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs); 1896872a481558350634a3fd5cb67939de288af00ecbJames Dong 1897872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Incremental video frame media time adjustment: %lld us", 1898872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs)); 1899872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1900872a481558350634a3fd5cb67939de288af00ecbJames Dong // Within the remaining adjustment period, 1901872a481558350634a3fd5cb67939de288af00ecbJames Dong // no incremental adjustment is needed. 1902872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1903872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs); 1904872a481558350634a3fd5cb67939de288af00ecbJames Dong 1905872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Fixed video frame media time adjustment: %lld us", 1906872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs)); 1907872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1908872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1909872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1910872a481558350634a3fd5cb67939de288af00ecbJames Dong 1911872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1912872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that 1913872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information 1914872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio 1915872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger 1916872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 1917872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined. 1918872a481558350634a3fd5cb67939de288af00ecbJames Dong */ 1919872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 1920872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftTimeUs = 0; 1921872a481558350634a3fd5cb67939de288af00ecbJames Dong if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 1922872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 1923872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 1924872a481558350634a3fd5cb67939de288af00ecbJames Dong mOwner->setDriftTimeUs(timeUs); 1925872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1926872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1927872a481558350634a3fd5cb67939de288af00ecbJames Dong 192837187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 192930ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 193013aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 193143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong const bool hasMultipleTracks = (mOwner->numTracks() > 1); 193213aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 193313aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 193413aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 19358f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 19368f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1937c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1938c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 19398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1940be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1941a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 19421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1943e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1944a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong if (mIsAudio) { 1945a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 1946a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } else { 1947a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 1948a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } 1949985f838934510983d8a887461e98dca60a6e858fJames Dong setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); 1950985f838934510983d8a887461e98dca60a6e858fJames Dong 1951d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 195220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1953ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 195493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 195520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 195693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 195720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 195820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 195920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 196013aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 196120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 196220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 196320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1964a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1965a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1966a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1967a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1968a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1969a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1970a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1971a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1972a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 197330ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 197430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 197503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 197603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 197703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1978548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1979548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 19801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 198103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 198203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 198303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 198403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1985be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 19861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 198703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 198803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 198903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 199003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 199103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 199203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 199330ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 199430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 199530ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 199630ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 199730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1998548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 199930ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 2000a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2001a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2002d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 2003d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 2004d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 2005d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 2006d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 2007d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 2008d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 2009d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 2010d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 2011d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 20121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 2013e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 2014b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong size_t sampleSize = copy->range_length(); 2015b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mIsAvc) { 2016b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 2017b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 4; 2018b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 2019b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 2; 2020b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 2021b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 2022050b28a593350047845a45a14cc5026221ac1620James Dong 2023d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 20241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes += sampleSize; 20251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong updateTrackSizeEstimate(); 20261f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 2027d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 2028d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2029d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2030d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2031d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 2032d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2033d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 2034d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 2035d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2036050b28a593350047845a45a14cc5026221ac1620James Dong 2037d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 2038d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2039d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 20408428af5381e835cc783b7ecb0d71cb60961c99c2James Dong /* 20418428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The original timestamp found in the data buffer will be modified as below: 20428428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20438428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * There is a playback offset into this track if the track's start time 20448428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is not the same as the movie start time, which will be recorded in edst 20458428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * box of the output file. The playback offset is to make sure that the 20468428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * starting time of the audio/video tracks are synchronized. Although the 20478428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * track's media timestamp may be subject to various modifications 20488428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * as outlined below, the track's playback offset time remains unchanged 20498428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * once the first data buffer of the track is received. 20508428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20518428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The media time stamp will be calculated by subtracting the playback offset 20528428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * (and potential pause durations) from the original timestamp in the buffer. 20538428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20548428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If this track is a video track for a real-time recording application with 20558428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * both audio and video tracks, its media timestamp will subject to further 20568428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * modification based on the media clock of the audio track. This modification 20578428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is needed for the purpose of maintaining good audio/video synchronization. 20588428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20598428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If the recording session is paused and resumed multiple times, the track 20608428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * media timestamp will be modified as if the recording session had never been 20618428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * paused at all during playback of the recorded output file. In other words, 20628428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * the output file will have no memory of pause/resume durations. 20638428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 20648428af5381e835cc783b7ecb0d71cb60961c99c2James Dong */ 2065d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 20668428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs); 2067d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 2068d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 206970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (mNumSamples == 0) { 207070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mFirstSampleTimeRealUs = systemTime() / 1000; 2071f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 2072f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 20738428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs = mStartTimestampUs; 20743c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 207548c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 2076a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 20778428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 20788428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(durExcludingEarlierPausesUs >= 0); 20798428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 20808428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(pausedDurationUs >= lastDurationUs); 20818428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs += pausedDurationUs - lastDurationUs; 2082a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 2083a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 2084a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2085a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 20868428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(timestampUs >= 0); 2087872a481558350634a3fd5cb67939de288af00ecbJames Dong 2088872a481558350634a3fd5cb67939de288af00ecbJames Dong // Media time adjustment for real-time applications 2089872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsRealTimeRecording) { 2090872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2091872a481558350634a3fd5cb67939de288af00ecbJames Dong updateDriftTime(meta_data); 2092872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 2093872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustMediaTime(×tampUs); 2094e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2095e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2096872a481558350634a3fd5cb67939de288af00ecbJames Dong 2097e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 2098e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 2099e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 21004f86a980fee1880dca61b828599fa6d76755a485James Dong LOGW("Frame arrives too late!"); 21014f86a980fee1880dca61b828599fa6d76755a485James Dong // Don't drop the late frame, since dropping a frame may cause 21024f86a980fee1880dca61b828599fa6d76755a485James Dong // problems later during playback 21034f86a980fee1880dca61b828599fa6d76755a485James Dong 21044f86a980fee1880dca61b828599fa6d76755a485James Dong // The idea here is to avoid having two or more samples with the 21054f86a980fee1880dca61b828599fa6d76755a485James Dong // same timestamp in the output file. 21064f86a980fee1880dca61b828599fa6d76755a485James Dong if (mTimeScale >= 1000000LL) { 210740e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + 1; 21084f86a980fee1880dca61b828599fa6d76755a485James Dong } else { 210940e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale; 21104f86a980fee1880dca61b828599fa6d76755a485James Dong } 2111e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2112e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 2113e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 21148428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s media time stamp: %lld and previous paused duration %lld", 21158428af5381e835cc783b7ecb0d71cb60961c99c2James Dong mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); 2116c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 2117c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 21183b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 21193b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 21208644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 2121ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 2122ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 2123c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 2124c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 2125c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 2126c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 2127c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 2128c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 2129c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 2130c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2131c059860c73678a202bfa33062723e8f82fb779d9James Dong 2132a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Force the first sample to have its own stts entry so that 2133a472613aec322e25891abf5c77bf3f7e3c244920James Dong // we can adjust its value later to maintain the A/V sync. 2134a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) { 2135a472613aec322e25891abf5c77bf3f7e3c244920James Dong LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us", 2136a472613aec322e25891abf5c77bf3f7e3c244920James Dong mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks); 213779761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount, lastDurationTicks); 2138be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 2139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2140be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 2141be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2142be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2143be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 2144ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 2145be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 2146be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 21478644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 2148be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2149a472613aec322e25891abf5c77bf3f7e3c244920James Dong LOGV("%s timestampUs/lastTimestampUs: %lld/%lld", 2150a472613aec322e25891abf5c77bf3f7e3c244920James Dong mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs); 21518644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 2152c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 21538644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 215420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2155d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 21561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStssTableEntry(mNumSamples); 2157d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 2158d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 215993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 216093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 216193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 216293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 2163faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 216493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 216543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 2166c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 216758ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 216858ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 21691f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addChunkOffset(offset); 217058ae9c530247668f8af36e30d228c716c226b3d4James Dong } 217158ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 217258ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 217358ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 217458ae9c530247668f8af36e30d228c716c226b3d4James Dong } 217513aec890216948b0c364f8f92792129d0335f506James Dong 217613aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 217713aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 21781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, 1); 21791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 218013aec890216948b0c364f8f92792129d0335f506James Dong } else { 218113aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 218213aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 218313aec890216948b0c364f8f92792129d0335f506James Dong } else { 218443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 218543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > interleaveDurationUs) { 218643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (chunkDurationUs > mMaxChunkDurationUs) { 218743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs = chunkDurationUs; 218843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 218913aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 219013aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 219113aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 219213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 21931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(nChunks, mChunkSamples.size()); 219413aec890216948b0c364f8f92792129d0335f506James Dong } 21951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 219613aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 219713aec890216948b0c364f8f92792129d0335f506James Dong } 219813aec890216948b0c364f8f92792129d0335f506James Dong } 219913aec890216948b0c364f8f92792129d0335f506James Dong } 220013aec890216948b0c364f8f92792129d0335f506James Dong 220120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 220225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 2203a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong if (mSampleSizes.empty() || // no samples written 2204a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (!mIsAudio && mNumStssTableEntries == 0) || // no sync frames for video 2205a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (OK != checkCodecSpecificData())) { // no codec specific data 2206690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 2207f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 2208bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, -1, err); 2209be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 221013aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 221143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (!hasMultipleTracks) { 22121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(1, mNumSamples); 221358ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 22141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, mChunkSamples.size()); 22151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 221613aec890216948b0c364f8f92792129d0335f506James Dong } 221713aec890216948b0c364f8f92792129d0335f506James Dong 2218be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 2219be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 2220be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 2221ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 22228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 222379761ab096f57c3027fad9556c2bc436672d614eJames Dong lastDurationTicks = 0; 2224be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2225be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 2226be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2227a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2228a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mNumSamples <= 2) { 222979761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(1, lastDurationTicks); 2230a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (sampleCount - 1 > 0) { 223179761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); 2232a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2233a472613aec322e25891abf5c77bf3f7e3c244920James Dong } else { 223479761ab096f57c3027fad9556c2bc436672d614eJames Dong addOneSttsTableEntry(sampleCount, lastDurationTicks); 2235a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2236a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2237c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 223825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 223943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 224043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong sendTrackSummary(hasMultipleTracks); 224143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 22421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 22431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video"); 2244872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2245872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); 2246872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2247365a963142093a1cd8efdcea76b5f65096a5b115James Dong 224837187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 224937187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 225037187916a486504acaf83bea30147eb5fbf46ae5James Dong } 225137187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 2252365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 2253365a963142093a1cd8efdcea76b5f65096a5b115James Dong 225443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 225507ec01904613a0bac32caaa8444b4690998faed7James Dong 225607ec01904613a0bac32caaa8444b4690998faed7James Dong // Send track summary only if test mode is enabled. 225707ec01904613a0bac32caaa8444b4690998faed7James Dong if (!isTestModeEnabled()) { 225807ec01904613a0bac32caaa8444b4690998faed7James Dong return; 225907ec01904613a0bac32caaa8444b4690998faed7James Dong } 226007ec01904613a0bac32caaa8444b4690998faed7James Dong 226143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong int trackNum = (mTrackId << 28); 226243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 226343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 226443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 226543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mIsAudio? 0: 1); 226643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 226743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 226843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 226943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mTrackDurationUs / 1000); 227043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 227143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 227243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 227343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mNumSamples); 227443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 227586b7f47aa7482424cf8fd248f1315311919be3b0James Dong { 227686b7f47aa7482424cf8fd248f1315311919be3b0James Dong // The system delay time excluding the requested initial delay that 227786b7f47aa7482424cf8fd248f1315311919be3b0James Dong // is used to eliminate the recording sound. 227886b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 227986b7f47aa7482424cf8fd248f1315311919be3b0James Dong if (startTimeOffsetUs < 0) { // Start time offset was not set 228086b7f47aa7482424cf8fd248f1315311919be3b0James Dong startTimeOffsetUs = kInitialDelayTimeUs; 228186b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 228286b7f47aa7482424cf8fd248f1315311919be3b0James Dong int64_t initialDelayUs = 228386b7f47aa7482424cf8fd248f1315311919be3b0James Dong mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 228486b7f47aa7482424cf8fd248f1315311919be3b0James Dong 228586b7f47aa7482424cf8fd248f1315311919be3b0James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 228670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 228770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong (initialDelayUs) / 1000); 228886b7f47aa7482424cf8fd248f1315311919be3b0James Dong } 228970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 229007ec01904613a0bac32caaa8444b4690998faed7James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 229107ec01904613a0bac32caaa8444b4690998faed7James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, 229207ec01904613a0bac32caaa8444b4690998faed7James Dong mMdatSizeBytes / 1024); 229307ec01904613a0bac32caaa8444b4690998faed7James Dong 229443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong if (hasMultipleTracks) { 229543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 229643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 229743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong mMaxChunkDurationUs / 1000); 229870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 229970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 230070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong if (mStartTimestampUs != moovStartTimeUs) { 230170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 230270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 230370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 230470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong startTimeOffsetUs / 1000); 230570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong } 230643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong } 230743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong} 230843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong 2309faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2310faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 2311215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 2312215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 231393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 2314bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 231593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 231693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 231793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 231893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 2319faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 2320bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong size_t trackId, int64_t timeUs, status_t err) { 2321faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 2322bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t trackNum = (trackId << 28); 2323faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2324faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 2325faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 2326faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 2327bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2328bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 2329faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2330faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2331faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2332faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2333faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 2334faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 2335bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2336bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 2337faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2338faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 2339faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 2340bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2341bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 2342faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 2343faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2344faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 2345faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2346d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2347d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong LOGV("setDriftTimeUs: %lld us", driftTimeUs); 2348e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2349d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 2350e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2351e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2352e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 2353e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 2354e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2355e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 2356e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2357e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2358b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() { 2359b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong return mUse4ByteNalLength; 2360b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong} 2361b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 23621c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 23631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 23641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 23651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 23661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 236713aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 236820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 236920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 23703b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 2371c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 237220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 237320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2374d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2375d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 2376d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 2377d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2378690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 2379690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 2380690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2381690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2382690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2383690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2384690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 2385690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 2386a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Missing codec specific data"); 2387690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2388690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2389690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 2390690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 2391690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 2392a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Unexepected codec specific data found"); 2393690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2394690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2395690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2396690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 2397690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 2398690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2399b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 240020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 24018f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 24021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 24038f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 240420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 2405b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("trak"); 2406b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeTkhdBox(now); 2407b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdia"); 2408b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMdhdBox(now); 2409b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeHdlrBox(); 2410b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("minf"); 2411b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2412b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSmhdBox(); 2413b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2414b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVmhdBox(); 2415b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2416b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDinfBox(); 2417b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStblBox(use32BitOffset); 2418b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // minf 2419b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mdia 2420b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // trak 2421b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2422b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2423b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 2424b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stbl"); 2425b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsd"); 2426b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2427b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count 2428b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2429b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAudioFourCCBox(); 2430b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2431b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeVideoFourCCBox(); 2432b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2433b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsd 2434b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeSttsBox(); 2435b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!mIsAudio) { 2436b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStssBox(); 2437b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2438b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStszBox(); 2439b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStscBox(); 2440b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeStcoBox(use32BitOffset); 2441b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stbl 2442b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2443b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2444b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() { 2445b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2446b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2447b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2448b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2449b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mp4v"); 2450b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2451b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("s263"); 2452b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2453b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("avc1"); 2454b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2455b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong LOGE("Unknown mime type '%s'.", mime); 2456b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2457b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2458b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2459b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2460b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2461b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // data ref index 2462b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2463b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2464b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2465b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2466b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // predefined 2467b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2468b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 2469b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeyWidth, &width); 2470b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 2471b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2472b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2473b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(width); 2474b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(height); 2475b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // horiz resolution 2476b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x480000); // vert resolution 2477b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2478b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(1); // frame count 2479b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(" ", 32); 2480b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x18); // depth 2481b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(-1); // predefined 2482b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2483b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(23 + mCodecSpecificDataSize < 128); 2484b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2485b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2486b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4vEsdsBox(); 2487b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2488b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeD263Box(); 2489b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2490b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeAvccBox(); 2491b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2492b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2493b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writePaspBox(); 2494b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // mp4v, s263 or avc1 2495b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2496b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2497b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() { 2498b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *mime; 2499b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findCString(kKeyMIMEType, &mime); 2500b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2501b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong const char *fourcc = NULL; 2502b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 2503b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "samr"; 2504b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2505b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "sawb"; 2506b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2507b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong fourcc = "mp4a"; 2508b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2509b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong LOGE("Unknown mime type '%s'.", mime); 2510b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(!"should not be here, unknown mime type."); 2511b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2512b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2513b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(fourcc); // audio format 2514b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2515b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2516b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x1); // data ref index 2517b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2518b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2519b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t nChannels; 2520b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2521b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(nChannels); // channel count 2522b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(16); // sample size 2523b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2524b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2525b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2526b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t samplerate; 2527b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = mMeta->findInt32(kKeySampleRate, &samplerate); 2528b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2529b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(samplerate << 16); 2530b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2531b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeMp4aEsdsBox(); 2532b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 2533b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2534b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDamrBox(); 2535b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2536b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2537b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2538b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2539b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() { 2540b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 2541b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 2542b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize > 0); 2543b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2544b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Make sure all sizes encode to a single byte. 2545b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize + 23 < 128); 2546b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2547b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2548b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 2549b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2550b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000);// ES_ID 2551b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x00); 2552b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2553b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2554b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2555b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2556b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x15); // streamType AudioStream 2557b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2558b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x03); // XXX 2559b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2560b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(96000); // max bit rate 2561b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(96000); // avg bit rate 2562b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2563b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2564b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 2565b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2566b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2567b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 2568b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 2569b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 2570b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 2571b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2572b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 2573b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2574b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 2575b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2576b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2577b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() { 2578b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 2579b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize > 0); 2580b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("esds"); 2581b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2582b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2583b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2584b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x03); // ES_DescrTag 2585b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2586b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x0000); // ES_ID 2587b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x1f); 2588b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2590b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2591b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 2592b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x11); // streamType VisualStream 2593b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2594b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData[] = { 2595b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 0x77, 0x00, 2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x00, 0x03, 0xe8, 0x00, 2597b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x00, 0x03, 0xe8, 0x00 2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData, sizeof(kData)); 2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2603b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(mCodecSpecificDataSize); 2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong static const uint8_t kData2[] = { 2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x06, // SLConfigDescriptorTag 2608b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x01, 2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 0x02 2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong }; 2611b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(kData2, sizeof(kData2)); 2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // esds 2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTkhdBox(time_t now) { 2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("tkhd"); 2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Flags = 7 to indicate that the track is enabled, and 2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // part of the presentation 2620b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x07); // version=0, flags=7 2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 2622b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 2623b5212db69734962f55e1493d3e696794172ced51James Dong mOwner->writeInt32(mTrackId + 1); // track id starts with 1 2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 26258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 2627b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t tkhdDuration = 2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2632b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // layer 2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // alternate group 2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCompositionMatrix(mRotation); // matrix 263820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mIsAudio) { 2640b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t width, height; 2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong bool success = mMeta->findInt32(kKeyWidth, &width); 2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong success = success && mMeta->findInt32(kKeyHeight, &height); 2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(success); 2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // tkhd 2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2654b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() { 2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("vmhd"); 2656b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0x01); // version=0, flags=1 2657b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // graphics mode 2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // opcolor 2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); 2661b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() { 2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("smhd"); 2666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // balance 2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // reserved 2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2670b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2671b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() { 2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("hdlr"); 2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2675b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // component type: should be mhlr 2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 2677b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // reserved 2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Removing "r" for the name string just makes the string 4 byte aligned 2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMdhdBox(time_t now) { 2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t trakDurationUs = getDurationUs(); 2687b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("mdhd"); 2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // creation time 2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(now); // modification time 2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mTimeScale); // media timescale 2692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mdhdDuration); // use media timescale 2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Language follows the three letter standard ISO-639-2/T 2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 'e', 'n', 'g' for "English", for instance. 2696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Each character is packed as the difference between its ASCII value and 0x60. 2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // For "English", these are 00101, 01110, 00111. 2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // XXX: Where is the padding bit located: 0x15C7? 2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // language code 2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0); // predefined 2701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() { 2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // 3gpp2 Spec AMRSampleEntry fields 2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("damr"); 2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeCString(" "); // vendor: 4 bytes 2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 2709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // mode change period 2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(1); // frames per sample 2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); 2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() { 2716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // The table index here refers to the sample description index 2717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // in the sample table entries. 2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("url "); 2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // url 2721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() { 2724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dref"); 2725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1); // entry count (either url or urn) 2727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeUrlBox(); 2728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dref 2729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() { 2732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("dinf"); 2733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong writeDrefBox(); 2734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // dinf 2735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() { 2738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificData); 2739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mCodecSpecificDataSize >= 5); 2740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // Patch avcc's lengthSize field to match the number 2742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong // of bytes we use to indicate the size of a nal unit. 2743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong uint8_t *ptr = (uint8_t *)mCodecSpecificData; 2744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 2745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("avcC"); 2746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // avcC 2748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() { 2751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("d263"); 2752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // vendor 2753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // decoder version 2754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(10); // level: 10 2755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt8(0); // profile: 0 2756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // d263 2757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square 2760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() { 2761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("pasp"); 2762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // hspacing 2763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(1 << 16); // vspacing 2764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // pasp 2765b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 2766b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong 2767b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSttsBox() { 2768b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stts"); 2769b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2770b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumSttsTableEntries); 277170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong 2772a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Compensate for small start time difference from different media tracks 2773a472613aec322e25891abf5c77bf3f7e3c244920James Dong int64_t trackStartTimeOffsetUs = 0; 2774b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 2775b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mStartTimestampUs != moovStartTimeUs) { 2776b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong CHECK(mStartTimestampUs > moovStartTimeUs); 2777b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 2778b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 277979761ab096f57c3027fad9556c2bc436672d614eJames Dong List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 278079761ab096f57c3027fad9556c2bc436672d614eJames Dong CHECK(it != mSttsTableEntries.end() && it->sampleCount == 1); 278179761ab096f57c3027fad9556c2bc436672d614eJames Dong mOwner->writeInt32(it->sampleCount); 278279761ab096f57c3027fad9556c2bc436672d614eJames Dong int32_t dur = (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL; 278379761ab096f57c3027fad9556c2bc436672d614eJames Dong mOwner->writeInt32(dur + it->sampleDuration); 2784a472613aec322e25891abf5c77bf3f7e3c244920James Dong 278579761ab096f57c3027fad9556c2bc436672d614eJames Dong while (++it != mSttsTableEntries.end()) { 278679761ab096f57c3027fad9556c2bc436672d614eJames Dong mOwner->writeInt32(it->sampleCount); 278779761ab096f57c3027fad9556c2bc436672d614eJames Dong mOwner->writeInt32(it->sampleDuration); 2788b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2789b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stts 2790b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 279120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2792b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() { 2793b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stss"); 2794b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2795b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumStssTableEntries); // number of sync frames 2796b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2797b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mStssTableEntries.end(); ++it) { 2798b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(*it); 2799b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2800b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stss 2801b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 280225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 2803b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() { 2804b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsz"); 2805b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2806b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (mSamplesHaveSameSize) { 2807b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong List<size_t>::iterator it = mSampleSizes.begin(); 2808b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(*it); // default sample size 2809b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2810b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); 2811b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2812b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumSamples); 2813b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (!mSamplesHaveSameSize) { 2814b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 2815b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mSampleSizes.end(); ++it) { 2816b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(*it); 2817b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2818b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2819b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsz 2820b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 282120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2822b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() { 2823b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox("stsc"); 2824b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2825b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumStscTableEntries); 2826b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 2827b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mStscTableEntries.end(); ++it) { 2828b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(it->firstChunk); 2829b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(it->samplesPerChunk); 2830b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(it->sampleDescriptionId); 2831b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2832b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stsc 2833b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong} 283420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2835b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 2836b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 2837b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(0); // version=0, flags=0 2838b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(mNumStcoTableEntries); 2839b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong for (List<off64_t>::iterator it = mChunkOffsets.begin(); 2840b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong it != mChunkOffsets.end(); ++it) { 2841b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong if (use32BitOffset) { 2842b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 2843b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } else { 2844b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->writeInt64((*it)); 2845b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2846b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong } 2847b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong mOwner->endBox(); // stco or co64 284820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 284920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 285007b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() { 285107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("udta"); 285207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeGeoDataBox(); 285307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 285407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 285507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 285607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/* 285707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard. 285807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 285907b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() { 286007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong beginBox("\xA9xyz"); 286107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong /* 286207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * For historical reasons, any user data start 286307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * with "\0xA9", must be followed by its assoicated 286407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * language code. 2865432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong * 0x0012: text string length 2866432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong * 0x15c7: lang (locale) code: en 286707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */ 286807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt32(0x001215c7); 286907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLatitude(mLatitudex10000); 287007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeLongitude(mLongitudex10000); 287107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong writeInt8(0x2F); 287207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong endBox(); 287307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong} 287407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong 287520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2876