MPEG4Writer.cpp revision 985f838934510983d8a887461e98dca60a6e858f
120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber/* 220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Copyright (C) 2009 The Android Open Source Project 320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * you may not use this file except in compliance with the License. 620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * You may obtain a copy of the License at 720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 1020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Unless required by applicable law or agreed to in writing, software 1120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 1220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * See the License for the specific language governing permissions and 1420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * limitations under the License. 1520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber */ 1620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 17050b28a593350047845a45a14cc5026221ac1620James Dong//#define LOG_NDEBUG 0 18050b28a593350047845a45a14cc5026221ac1620James Dong#define LOG_TAG "MPEG4Writer" 19050b28a593350047845a45a14cc5026221ac1620James Dong#include <utils/Log.h> 20050b28a593350047845a45a14cc5026221ac1620James Dong 2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h> 2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h> 24a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/prctl.h> 25a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/resource.h> 2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 2920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 300c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h> 3118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 3203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 35d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h> 36674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/types.h> 37674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/stat.h> 38674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <fcntl.h> 39674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <unistd.h> 4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 4219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL; 463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 485b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong 495b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// Using longer adjustment period to suppress fluctuations in 505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// the audio encoding paths 515b6a01e65aa4129a9226667536d1bc1dad5980d8James Dongstatic const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL; // 10 minutes 523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 5320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 5525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track(MPEG4Writer *owner, const sp<MediaSource> &source); 568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 5720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 5820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 6037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 6137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 6225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 6320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 643b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 65d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 661acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); 671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 71c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong void addChunkOffset(off64_t offset); 72dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong status_t dump(int fd, const Vector<String16>& args) const; 7320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 7520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 7620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 77693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 7820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 79a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 80a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 84c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 85e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 86e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // For realtime applications, we need to adjust the media clock 87e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // for video track based on the audio media clock 88e259531ce59ab1f31de5a23124b22536f6a5a767James Dong bool mIsRealTimeRecording; 89e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t mMaxTimeStampUs; 90d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t mMdatSizeBytes; 928f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 9320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 9520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 96ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // mNumSamples is used to track how many samples in mSampleSizes List. 97ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // This is to reduce the cost associated with mSampleSizes.size() call, 98ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // since it is O(n). Ideally, the fix should be in List class. 99ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong size_t mNumSamples; 1008644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t> mSampleSizes; 101be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 102be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 10313aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 1041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStcoTableEntries; 106c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong List<off64_t> mChunkOffsets; 10713aec890216948b0c364f8f92792129d0335f506James Dong 1081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStscTableEntries; 10913aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 11013aec890216948b0c364f8f92792129d0335f506James Dong 11113aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 11213aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 11313aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 11413aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 11513aec890216948b0c364f8f92792129d0335f506James Dong 11613aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 11713aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 11813aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 11913aec890216948b0c364f8f92792129d0335f506James Dong }; 12013aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 12120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStssTableEntries; 123050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 124050b28a593350047845a45a14cc5026221ac1620James Dong 1251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumSttsTableEntries; 126be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 127be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry(uint32_t count, uint32_t durationUs) 1298f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong : sampleCount(count), sampleDurationUs(durationUs) {} 130be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 131be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 1328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong uint32_t sampleDurationUs; 133be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 134be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 135be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 1373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 1383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 1393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 1403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 1463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 1473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 1483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 15120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 152548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 15393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 15420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 15525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1563c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 15793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 15893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 15925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 160872a481558350634a3fd5cb67939de288af00ecbJames Dong // Has the media time adjustment for video started? 161872a481558350634a3fd5cb67939de288af00ecbJames Dong bool mIsMediaTimeAdjustmentOn; 162872a481558350634a3fd5cb67939de288af00ecbJames Dong // The time stamp when previous media time adjustment period starts 163872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustTimestampUs; 164872a481558350634a3fd5cb67939de288af00ecbJames Dong // Number of vidoe frames whose time stamp may be adjusted 165872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mMediaTimeAdjustNumFrames; 166872a481558350634a3fd5cb67939de288af00ecbJames Dong // The sample number when previous meida time adjustmnet period starts 167872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustSample; 168872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumulated drift time within a period of 169872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 170872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mTotalDriftTimeToAdjustUs; 171872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumalated drift time since the start of the recording 172872a481558350634a3fd5cb67939de288af00ecbJames Dong // excluding the current time adjustment period 173872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevTotalAccumDriftTimeUs; 174872a481558350634a3fd5cb67939de288af00ecbJames Dong 175872a481558350634a3fd5cb67939de288af00ecbJames Dong // Update the audio track's drift information. 176872a481558350634a3fd5cb67939de288af00ecbJames Dong void updateDriftTime(const sp<MetaData>& meta); 177872a481558350634a3fd5cb67939de288af00ecbJames Dong 178872a481558350634a3fd5cb67939de288af00ecbJames Dong // Adjust the time stamp of the video track according to 179872a481558350634a3fd5cb67939de288af00ecbJames Dong // the drift time information from the audio track. 180872a481558350634a3fd5cb67939de288af00ecbJames Dong void adjustMediaTime(int64_t *timestampUs); 181872a481558350634a3fd5cb67939de288af00ecbJames Dong 18220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 18337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 1863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 1873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 18803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t makeAVCCodecSpecificData( 18903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size); 1903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t copyAVCCodecSpecificData( 1913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 1923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t parseAVCCodecSpecificData( 1933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 194215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 195215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 196faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 19793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 19803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 19919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 20019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 201c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 202c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 203c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 204c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 205c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 206c059860c73678a202bfa33062723e8f82fb779d9James Dong 207690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 208690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 20913f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t mRotation; 210690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void updateTrackSizeEstimate(); 2121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStscTableEntry(size_t chunkId, size_t sampleId); 2131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStssTableEntry(size_t sampleId); 2141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs); 2151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 21620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 21720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22020111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 221674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(-1), 222674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(NO_INIT), 223b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2241acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 225a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 226a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 227a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 22820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 22913aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2307837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 231f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 232674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong 233674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC); 234674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mFd >= 0) { 235674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = OK; 236674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong } 23720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 23820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 23930ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 240674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(dup(fd)), 241674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(mFd < 0? NO_INIT: OK), 242b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 244a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 245a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 246a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 24730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 24813aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2497837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 250f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 25130ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 25230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 25320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 25420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 25520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong while (!mTracks.empty()) { 2571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong List<Track *>::iterator it = mTracks.begin(); 25820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 2591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong (*it) = NULL; 2601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mTracks.erase(it); 26120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 26220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 26320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 26420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 265dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 266dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 267dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 268dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 269dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 270dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 271dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 272dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 273dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 274dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 275dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 276dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 277dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 278dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 279dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 280dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 281dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 282dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 283dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) const { 284dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 285dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 286dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 287dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 288dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 289dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 290dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 291dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 292dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 293dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 294dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 295dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 2962dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 29725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track *track = new Track(this, source); 29820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 2992dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 3002dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 30120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 30220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 30393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 304a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 305a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 30693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 307a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 308a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 309a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 310a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 311a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 312a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 313a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 314a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 315a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 316a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 317a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 318a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 319a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3202dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 3212dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 3222dec2b5be2056c6d9428897dc672185872d30d17James Dong // 3232dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 3242dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 3252dec2b5be2056c6d9428897dc672185872d30d17James Dong 32678a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 3272dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 32878a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 3 3292dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 3302dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 3312dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 3322dec2b5be2056c6d9428897dc672185872d30d17James Dong 3332dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 3342dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 3352dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 33678a1a286f736888ae7af8860b2c424af0d978848James Dong static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 3372dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 3382dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 3392dec2b5be2056c6d9428897dc672185872d30d17James Dong 34078a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file size limit is set 341a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 34278a1a286f736888ae7af8860b2c424af0d978848James Dong size = mMaxFileSizeLimitBytes * 6 / 1000; 34378a1a286f736888ae7af8860b2c424af0d978848James Dong } 34478a1a286f736888ae7af8860b2c424af0d978848James Dong 34578a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file duration limit is set 34678a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileDurationLimitUs != 0) { 34778a1a286f736888ae7af8860b2c424af0d978848James Dong if (bitRate > 0) { 34878a1a286f736888ae7af8860b2c424af0d978848James Dong int64_t size2 = 34978a1a286f736888ae7af8860b2c424af0d978848James Dong ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 35078a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 35178a1a286f736888ae7af8860b2c424af0d978848James Dong // When both file size and duration limits are set, 35278a1a286f736888ae7af8860b2c424af0d978848James Dong // we use the smaller limit of the two. 35378a1a286f736888ae7af8860b2c424af0d978848James Dong if (size > size2) { 35478a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 35578a1a286f736888ae7af8860b2c424af0d978848James Dong } 35678a1a286f736888ae7af8860b2c424af0d978848James Dong } else { 35778a1a286f736888ae7af8860b2c424af0d978848James Dong // Only max file duration limit is set 35878a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 35978a1a286f736888ae7af8860b2c424af0d978848James Dong } 3602dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3612dec2b5be2056c6d9428897dc672185872d30d17James Dong } 36278a1a286f736888ae7af8860b2c424af0d978848James Dong 3632dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 3642dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 3652dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3662dec2b5be2056c6d9428897dc672185872d30d17James Dong 3672dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 3682dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 3692dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 3702dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 3712dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3722dec2b5be2056c6d9428897dc672185872d30d17James Dong 373a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 3742dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 3752dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 3762dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 3772dec2b5be2056c6d9428897dc672185872d30d17James Dong} 3782dec2b5be2056c6d9428897dc672185872d30d17James Dong 3792dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 380674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 38125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 38220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 38320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 384a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong /* 385a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * Check mMaxFileSizeLimitBytes at the beginning 386a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * since mMaxFileSizeLimitBytes may be implicitly 387a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * changed later for 32-bit file offset even if 388a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * user does not ask to set it explicitly. 389a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong */ 390a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0) { 391a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested = true; 392a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong } 393a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong 3942dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 3952dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 3962dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 3972dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 3982dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 3992dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4002dec2b5be2056c6d9428897dc672185872d30d17James Dong 4011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mUse32BitOffset) { 4021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // Implicit 32 bit file size limit 4031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes == 0) { 4041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 4071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // If file size is set to be larger than the 32 bit file 4081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // size limit, treat it as an error. 4091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 410872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGW("32-bit file size limit (%lld bytes) too big. " 411d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong "It is changed to %lld bytes", 412d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes, kMax32BitFileSize); 413d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 417b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong int32_t use2ByteNalLength; 418b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (param && 419b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 420b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong use2ByteNalLength) { 421b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength = false; 4222dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4232dec2b5be2056c6d9428897dc672185872d30d17James Dong 424065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 42593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 426a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 427a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 428a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 42993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 430a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 431a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 432a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 433a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 4348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 4358f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 4368f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 4378f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 4388f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 4398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 4408f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 4417837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 4427837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 4437837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 4447837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4457837c17063a4c50bc856ba59418516fdab731de7James Dong 44620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 44793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 44893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int32_t fileType; 44993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (param && param->findInt32(kKeyFileType, &fileType) && 45093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong fileType != OUTPUT_FORMAT_MPEG_4) { 45193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 45293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } else { 45393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("isom"); 45493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 45593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 45620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 45720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 45893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 45920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 46020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4617837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 46220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4637837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 4642dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 4652dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 4662dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 4672dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4682dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 4697837c17063a4c50bc856ba59418516fdab731de7James Dong } 4707837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 471c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 4727837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 4737837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 4747837c17063a4c50bc856ba59418516fdab731de7James Dong 4757837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 4767837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 477c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 4781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 4791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 4801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 4811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 4821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 4831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 4851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 4861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 4871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 4881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 490a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 491a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 49220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 4931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 494a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 49525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 49620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 49720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4981f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const { 4991f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong return mUse32BitOffset; 5001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 5011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 50237187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 503674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 50437187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 505a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 506a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 50737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 508a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 509a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 51037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 51137187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 51237187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 51337187916a486504acaf83bea30147eb5fbf46ae5James Dong } 514a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 51537187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 516a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 517a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 5181c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 519cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping writer thread"); 5201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 5221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 5231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 5251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 5261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 5271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 5291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 530cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Writer thread stopped"); 5311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 5321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 53313f6284305e4b27395a23db7882d670bdb1bcae1James Dong/* 53413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix: 53513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a b u | 53613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c d v | 53713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x y w | 53813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * 53913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following 54013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w}, 54113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while 54213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format. 54313f6284305e4b27395a23db7882d670bdb1bcae1James Dong */ 54413f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) { 54513f6284305e4b27395a23db7882d670bdb1bcae1James Dong LOGV("writeCompositionMatrix"); 54613f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t a = 0x00010000; 54713f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t b = 0; 54813f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t c = 0; 54913f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t d = 0x00010000; 55013f6284305e4b27395a23db7882d670bdb1bcae1James Dong switch (degrees) { 55113f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 0: 55213f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 55313f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 90: 55413f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 55513f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0x00010000; 55613f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0xFFFF0000; 55713f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 55813f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 55913f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 180: 56013f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0xFFFF0000; 56113f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0xFFFF0000; 56213f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 56313f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 270: 56413f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 56513f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0xFFFF0000; 56613f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0x00010000; 56713f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 56813f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 56913f6284305e4b27395a23db7882d670bdb1bcae1James Dong default: 57013f6284305e4b27395a23db7882d670bdb1bcae1James Dong CHECK(!"Should never reach this unknown rotation"); 57113f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 57213f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 57313f6284305e4b27395a23db7882d670bdb1bcae1James Dong 57413f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(a); // a 57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(b); // b 57613f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // u 57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(c); // c 57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(d); // d 57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // v 58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // x 58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // y 58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0x40000000); // w 58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong} 58413f6284305e4b27395a23db7882d670bdb1bcae1James Dong 58513f6284305e4b27395a23db7882d670bdb1bcae1James Dong 58637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() { 587674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 58837187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 58920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 59020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 59137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 5928f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 59320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 59420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 59537187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 59637187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 59737187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 59837187916a486504acaf83bea30147eb5fbf46ae5James Dong } 59920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6008f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 6018f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 6028f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 60320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 60420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 60520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 6077837c17063a4c50bc856ba59418516fdab731de7James Dong 60837187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 60937187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 610674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 611674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 612674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 61337187916a486504acaf83bea30147eb5fbf46ae5James Dong mStarted = false; 61437187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 61537187916a486504acaf83bea30147eb5fbf46ae5James Dong } 61637187916a486504acaf83bea30147eb5fbf46ae5James Dong 61720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 6181acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 619c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 6201acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 621c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 4); 6221acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 623c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset + 8, SEEK_SET); 6241acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 6251acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 626c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 8); 6271acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 628c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 62920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 63020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 631c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong const off64_t moovOffset = mOffset; 6327837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 6337837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 6347837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6357837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 636c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6; 63720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 63820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 63920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 64120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 64220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 6448f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong writeInt32(mTimeScale); // mvhd timescale 6451acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(duration); 6461acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(0x10000); // rate: 1.0 64720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 64820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 65020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 65113f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeCompositionMatrix(0); // matrix 65220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 65320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 65420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 65520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 65620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 65720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 65820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 66020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 66120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 66220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 66320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 6641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong (*it)->writeTrackHeader(id, mUse32BitOffset); 66520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 66720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6687837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6697837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 6707837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 6717837c17063a4c50bc856ba59418516fdab731de7James Dong 6727837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 673c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 6747837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 675674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 6767837c17063a4c50bc856ba59418516fdab731de7James Dong 6777837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 678c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 6797837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 6807837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 6817837c17063a4c50bc856ba59418516fdab731de7James Dong 6827837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 6837837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 6847837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6857837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6862dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 6872dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 6887837c17063a4c50bc856ba59418516fdab731de7James Dong } 6897837c17063a4c50bc856ba59418516fdab731de7James Dong 6900c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 69120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 692674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 693674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 694674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 695a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 69637187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69913aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 70013aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 70113aec890216948b0c364f8f92792129d0335f506James Dong return OK; 70213aec890216948b0c364f8f92792129d0335f506James Dong} 70313aec890216948b0c364f8f92792129d0335f506James Dong 70413aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 70513aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 70613aec890216948b0c364f8f92792129d0335f506James Dong} 70713aec890216948b0c364f8f92792129d0335f506James Dong 70813aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 70913aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 71013aec890216948b0c364f8f92792129d0335f506James Dong} 71120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 712c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 713c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 71420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 715c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 716c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 717c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong buffer->range_length()); 71820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 72020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 72120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 72220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 72320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 72403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 72503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 72603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 72703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 72803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 72903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 73003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 73103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 73203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 73303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 73403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 73503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 73603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 73703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 738c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 739c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 74030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 74130ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 74203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 743b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mUse4ByteNalLength) { 744b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 24; 745c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 746b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 16) & 0xff; 747c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 748b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 8) & 0xff; 749c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 750b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 751c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 752c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong 753c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 754c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 755c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong length); 756b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 757b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 4; 758b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 759b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong CHECK(length < 65536); 76030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 761b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 8; 762c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 763b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 764c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 765c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 766b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 2; 767b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 76830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 76930ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 77030ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 77130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 7727837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 773674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong const void *ptr, size_t size, size_t nmemb) { 7747837c17063a4c50bc856ba59418516fdab731de7James Dong 7757837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 7767837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 777674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // This happens only when we write the moov box at the end of 778674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // recording, not for each output video/audio frame we receive. 779c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 7801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 781c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mBoxes.begin(); 7827837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 7837837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 7847837c17063a4c50bc856ba59418516fdab731de7James Dong } 785674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong lseek64(mFd, mOffset, SEEK_SET); 786674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 787674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 7887837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 7897837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 7907837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 7917837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 7927837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 7937837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 7947837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 7957837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 7967837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 7977837c17063a4c50bc856ba59418516fdab731de7James Dong } 7987837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 799674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 8007837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 8017837c17063a4c50bc856ba59418516fdab731de7James Dong } 8027837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 8037837c17063a4c50bc856ba59418516fdab731de7James Dong} 8047837c17063a4c50bc856ba59418516fdab731de7James Dong 80520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 8060c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 80720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8087837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 8097837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 81020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 81120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 81220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 81320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 81420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 81520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 8160c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 81720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 818c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = *--mBoxes.end(); 81920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 82020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8217837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 8227837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 8237837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 8247837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 825c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, offset, SEEK_SET); 8267837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 8277837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 828c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 8297837c17063a4c50bc856ba59418516fdab731de7James Dong } 83020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 833674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 1); 83420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 83720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 838674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 2); 83920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 84020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 84220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 843674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 4); 84420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 84520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 84720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 848674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 8); 84920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 85020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 85220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 853674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, n + 1); 85420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 85520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 8570c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 858674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, 4); 85920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 86020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 86120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 862674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(data, 1, size); 86320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 86420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 86578a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const { 86678a1a286f736888ae7af8860b2c424af0d978848James Dong return mStreamableFile; 86778a1a286f736888ae7af8860b2c424af0d978848James Dong} 86878a1a286f736888ae7af8860b2c424af0d978848James Dong 869d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 870d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 871d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 872d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 873d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 874d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 875956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 876d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 877d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 878d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 879d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 8801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 881acd234bba9f048971d66890009eeff9a8db94be3James Dong // Be conservative in the estimate: do not exceed 95% of 882acd234bba9f048971d66890009eeff9a8db94be3James Dong // the target file limit. For small target file size limit, though, 883acd234bba9f048971d66890009eeff9a8db94be3James Dong // this will not help. 884acd234bba9f048971d66890009eeff9a8db94be3James Dong return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 885d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 886d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 887d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 888d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 889d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 890d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 891d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 892d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 893d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 894d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 895d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 896d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 897d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 898d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 899d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 900d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 901d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 90225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 90325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 90425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 90525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 90625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 90725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 90825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 90925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 91025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 91125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 91225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 91325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 91425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 915f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 916f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 917f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 9183c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 919065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 920f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 921f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 9223c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 9233c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 9243c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 925f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 9263c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 9273c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 9283c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 9293c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 93058ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 93158ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 93258ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 93358ae9c530247668f8af36e30d228c716c226b3d4James Dong} 93458ae9c530247668f8af36e30d228c716c226b3d4James Dong 93520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 93620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 93720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 93825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber MPEG4Writer *owner, const sp<MediaSource> &source) 93920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 94025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 94120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 94220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 943a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 944a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 945c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 946956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 947be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 94820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 94925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 950548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 95113f6284305e4b27395a23db7882d670bdb1bcae1James Dong mReachedEOS(false), 95213f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation(0) { 95319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 9548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 9551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 9561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 9571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 9581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 9591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 9601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 9611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 962c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 963c059860c73678a202bfa33062723e8f82fb779d9James Dong} 964c059860c73678a202bfa33062723e8f82fb779d9James Dong 9651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() { 9661f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9671f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset() 9681f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ? mNumStcoTableEntries * 4 9691f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong : mNumStcoTableEntries * 8; 9701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4); 9721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 97378a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 97478a1a286f736888ae7af8860b2c424af0d978848James Dong if (!mOwner->isFileStreamable()) { 97578a1a286f736888ae7af8860b2c424af0d978848James Dong // Reserved free space is not large enough to hold 97678a1a286f736888ae7af8860b2c424af0d978848James Dong // all meta data and thus wasted. 97778a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 + // stsc box size 97878a1a286f736888ae7af8860b2c424af0d978848James Dong mNumStssTableEntries * 4 + // stss box size 97978a1a286f736888ae7af8860b2c424af0d978848James Dong mNumSttsTableEntries * 8 + // stts box size 98078a1a286f736888ae7af8860b2c424af0d978848James Dong stcoBoxSizeBytes + // stco box size 98178a1a286f736888ae7af8860b2c424af0d978848James Dong stszBoxSizeBytes; // stsz box size 98278a1a286f736888ae7af8860b2c424af0d978848James Dong } 9831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry( 9861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t chunkId, size_t sampleId) { 9871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9881f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong StscTableEntry stscEntry(chunkId, sampleId, 1); 9891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStscTableEntries.push_back(stscEntry); 9901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStscTableEntries; 9911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 9941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStssTableEntries.push_back(sampleId); 9951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStssTableEntries; 9961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 9971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9981f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry( 9991f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t sampleCount, int64_t durationUs) { 10001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 10011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong SttsTableEntry sttsEntry(sampleCount, durationUs); 10021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mSttsTableEntries.push_back(sttsEntry); 10031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumSttsTableEntries; 10041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 10051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1006c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) { 10071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStcoTableEntries; 10081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mChunkOffsets.push_back(offset); 10091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 10101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1011c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 1012c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 1013c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 1014c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 1015c059860c73678a202bfa33062723e8f82fb779d9James Dong 1016c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 1017c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 1018c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 1019c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1020c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 1021c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 1022c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1023c059860c73678a202bfa33062723e8f82fb779d9James Dong 1024c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 1025c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 1026c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1027c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 1028c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1029c059860c73678a202bfa33062723e8f82fb779d9James Dong 10308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 103119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 103219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 103319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 103419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 103519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 103619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 103719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 103819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 103919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 104019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 104119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 104219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 104319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 104419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 104519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 104619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 104719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 104819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 104919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 105019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 105119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 105219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 105319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 105419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 105519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 105619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 105719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 105819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 105919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 106019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 106119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 106220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 106320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 106420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 106520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 106620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 106720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 106820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 106920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 107020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 107120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 107220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 107393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 107493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 107593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 107693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 107793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 107893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 107993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 108093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 108193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 108293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 108393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 108493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 108593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 108693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 108793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 10881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 10891c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 10901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 10911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 10921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 10931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 10941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 10951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10961c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 10971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 10981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 10991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 11001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 11031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 11051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 11061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 11071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 11081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 11121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11141c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeFirstChunk(ChunkInfo* info) { 11151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeFirstChunk: %p", info->mTrack); 11161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = info->mChunks.begin(); 11181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 11191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != chunkIt->mSamples.end(); ++it) { 11201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1121c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = info->mTrack->isAvc() 11221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ? addLengthPrefixedSample_l(*it) 11231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong : addSample_l(*it); 11241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it == chunkIt->mSamples.begin()) { 11251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mTrack->addChunkOffset(offset); 11261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Done with the current chunk. 11301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Release all the samples in this chunk. 11311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!chunkIt->mSamples.empty()) { 11321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 11331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 11341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 11351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.erase(it); 11361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.clear(); 11381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mChunks.erase(chunkIt); 11391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11411c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeChunks() { 11421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeChunks"); 11431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 11441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mChunkInfos.empty()) { 11451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!it->mChunks.empty()) { 11471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(OK, writeOneChunk()); 11481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ++outstandingChunks; 11491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mTrack = NULL; 11511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.erase(it); 11521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 11541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 11551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11571c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::writeOneChunk() { 11581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeOneChunk"); 11591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Find the smallest timestamp, and write that chunk out 11611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // XXX: What if some track is just too slow? 11621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 11631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 11641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 11661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 11671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 11681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 11691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 11701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 11711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 11761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 11771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 11781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 11811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 11821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 11851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 11861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeFirstChunk(&(*it)); 11871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 11901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11921c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 11931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 11941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1195a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 11961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 11971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 11981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 11991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 12001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(writeOneChunk(), OK); 12011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 12051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Write ALL samples 12061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 12071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeChunks(); 12081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12111c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 12121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 12131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 12151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1216e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 12171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 12181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 12191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 12201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 12211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 12221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 12251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 12261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 12271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 12281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 12291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 12301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 123393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1234a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1235a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1236a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1237a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1238a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 123925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 124093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 124119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 124219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 124319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 124419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 124513f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t rotationDegrees; 124613f6284305e4b27395a23db7882d670bdb1bcae1James Dong if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 124713f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation = rotationDegrees; 124813f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 124913f6284305e4b27395a23db7882d670bdb1bcae1James Dong 12505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong mIsRealTimeRecording = true; 1251e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1252e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1253e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1254e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1255e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1256e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1257e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 125893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 125993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1260f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1261f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1262f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 126325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 126425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 126525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 126625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 126720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 126820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 126920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 127020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 127120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 127220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1273c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 127425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1275956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 12761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStcoTableEntries = 0; 12771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStssTableEntries = 0; 12781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStscTableEntries = 0; 12791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumSttsTableEntries = 0; 12801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes = 0; 1281872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = false; 1282872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = 0; 1283872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 0; 1284872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = 0; 1285872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 0; 1286872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = 0; 128720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 128825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 128920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 129025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 129125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 129220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 129320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 129437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1295a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 129637187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1297a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1298a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 129937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 1300cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track", mIsAudio? "Audio": "Video"); 130120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 130237187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 130320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 130420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 130520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 130620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 130720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 130820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 130920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 131037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = (status_t) dummy; 131137187916a486504acaf83bea30147eb5fbf46ae5James Dong 1312cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track source", mIsAudio? "Audio": "Video"); 131337187916a486504acaf83bea30147eb5fbf46ae5James Dong { 131437187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = mSource->stop(); 131537187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { 131637187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 131737187916a486504acaf83bea30147eb5fbf46ae5James Dong } 131837187916a486504acaf83bea30147eb5fbf46ae5James Dong } 131937187916a486504acaf83bea30147eb5fbf46ae5James Dong 1320cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("%s track stopped", mIsAudio? "Audio": "Video"); 132137187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 132220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 132320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 132425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 132525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 132625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 132725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 132820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 132920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 133020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 133120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 133237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 133337187916a486504acaf83bea30147eb5fbf46ae5James Dong return (void *) err; 133420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 133520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 13363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 13373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 13383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 13403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 13413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 13443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 13453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 13473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 13493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 13503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 13513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 13523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 13543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 13553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 13573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 13603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 13613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 13633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 13643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 13653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 13673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 13683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 13693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 13703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 13713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 13743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 13753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 13763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 13773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 13783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 13803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 13813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 13823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 13833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 13843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 13853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 13863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 13873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 13883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 13893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 13923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 13933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 13943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 13963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 13993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 14003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 14013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 14033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 14043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 14053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 14063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 14103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 14113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 14123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 14133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 14143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 14163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 14173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 14193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 14203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 14213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 14223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 14233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 14243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 14253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 14263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 14273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 14283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 14293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 14303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 14313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 14323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 14333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 14343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 14353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 14383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 14393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 14413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 14423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 14433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 14443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 14473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 14483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 14503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 14513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 14523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 14563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 14603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 14613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 14623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 14633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 14663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 14673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 14683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 14693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 14703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 14743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 14753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 14803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 14813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 14823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 14833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 14843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 14873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 14883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 14933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 14943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 14953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 14963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 14973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 14983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 14993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 15033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1504548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 150503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 150603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1507548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 150803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1509548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 151003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 151103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 151203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 15143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 151503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 151603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 151703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 15193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 15203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 152103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 152203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 152403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 152503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 152603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 15283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 152903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 153003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 15313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 15323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 15333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 15343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 153503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 1537b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1538b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 3; // length size == 4 bytes 1539b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1540b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 1; // length size == 2 bytes 1541b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 154203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 15443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 15453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 15463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 15533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 15553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 15563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 15573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 15603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 15613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 15623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 15633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 15643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 15653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 15663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 15673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 15683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 15693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 15713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 15723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 15733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 157403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 157503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 157603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 157703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1578872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1579872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications 1580872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows: 1581872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1582872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of 1583872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs 1584872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of 1585872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small 1586872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value 1587872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding 1588872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep 1589872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the 1590872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is 1591872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track. 1592872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1593872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found 1594872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed 1595872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames 1596872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames 1597872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period. 1598872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion 1599872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames 1600872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is 1601872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media 1602872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a 1603872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5). 1604872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1605872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that 1606872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift. 1607872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time 1608872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold 1609872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs. 1610872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental 1611872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the 1612872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift. 1613872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio 1614872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of 1615872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold 1616872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of 1617872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio 1618872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time 1619872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no 1620872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time 1621872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some 1622872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want 1623872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being. 1624872a481558350634a3fd5cb67939de288af00ecbJames Dong*/ 1625872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) { 1626872a481558350634a3fd5cb67939de288af00ecbJames Dong if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >= 1627872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs) { 1628872a481558350634a3fd5cb67939de288af00ecbJames Dong 1629872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("New media time adjustment period at %lld us", *timestampUs); 1630872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = true; 1631872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 1632872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample) >> 1; 1633872a481558350634a3fd5cb67939de288af00ecbJames Dong 1634872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = *timestampUs; 1635872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = mNumSamples; 1636872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs(); 1637872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 1638872a481558350634a3fd5cb67939de288af00ecbJames Dong totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs; 1639872a481558350634a3fd5cb67939de288af00ecbJames Dong 1640872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs; 1641872a481558350634a3fd5cb67939de288af00ecbJames Dong 1642872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on incremental adjusted time per frame 1643872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t adjustTimePerFrameUs = 1644872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames; 1645872a481558350634a3fd5cb67939de288af00ecbJames Dong 1646872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs < 0) { 1647872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs = -adjustTimePerFrameUs; 1648872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1649872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs >= 5000) { 1650872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Adjusted time per video frame is %lld us", 1651872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs); 1652872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"Video frame time adjustment is too large!"); 1653872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1654872a481558350634a3fd5cb67939de288af00ecbJames Dong 1655872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on total accumulated time drift within a period of 1656872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 1657872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000) 1658872a481558350634a3fd5cb67939de288af00ecbJames Dong / kVideoMediaTimeAdjustPeriodTimeUs; 1659872a481558350634a3fd5cb67939de288af00ecbJames Dong 1660872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage < 0) { 1661872a481558350634a3fd5cb67939de288af00ecbJames Dong driftPercentage = -driftPercentage; 1662872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1663872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage > 5) { 1664872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Audio track has time drift %lld us over %lld us", 1665872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs, 1666872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs); 1667872a481558350634a3fd5cb67939de288af00ecbJames Dong 1668872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"The audio track media time drifts too much!"); 1669872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1670872a481558350634a3fd5cb67939de288af00ecbJames Dong 1671872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1672872a481558350634a3fd5cb67939de288af00ecbJames Dong 1673872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsMediaTimeAdjustmentOn) { 1674872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mNumSamples - mPrevMediaTimeAdjustSample <= 1675872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames) { 1676872a481558350634a3fd5cb67939de288af00ecbJames Dong 1677872a481558350634a3fd5cb67939de288af00ecbJames Dong // Do media time incremental adjustment 1678872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t incrementalAdjustTimeUs = 1679872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs * 1680872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample)) 1681872a481558350634a3fd5cb67939de288af00ecbJames Dong / mMediaTimeAdjustNumFrames; 1682872a481558350634a3fd5cb67939de288af00ecbJames Dong 1683872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1684872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs); 1685872a481558350634a3fd5cb67939de288af00ecbJames Dong 1686872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Incremental video frame media time adjustment: %lld us", 1687872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs)); 1688872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1689872a481558350634a3fd5cb67939de288af00ecbJames Dong // Within the remaining adjustment period, 1690872a481558350634a3fd5cb67939de288af00ecbJames Dong // no incremental adjustment is needed. 1691872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1692872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs); 1693872a481558350634a3fd5cb67939de288af00ecbJames Dong 1694872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Fixed video frame media time adjustment: %lld us", 1695872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs)); 1696872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1697872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1698872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1699872a481558350634a3fd5cb67939de288af00ecbJames Dong 1700872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1701872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that 1702872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information 1703872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio 1704872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger 1705872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 1706872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined. 1707872a481558350634a3fd5cb67939de288af00ecbJames Dong */ 1708872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 1709872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftTimeUs = 0; 1710872a481558350634a3fd5cb67939de288af00ecbJames Dong if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 1711872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 1712872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 1713872a481558350634a3fd5cb67939de288af00ecbJames Dong mOwner->setDriftTimeUs(timeUs); 1714872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1715872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1716872a481558350634a3fd5cb67939de288af00ecbJames Dong 171737187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 171830ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 171913aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 172013aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 172113aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 172213aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 17238f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 17248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1725c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1726c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 17278f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1728be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1729a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 17301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1731e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1732a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong if (mIsAudio) { 1733a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 1734a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } else { 1735a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 1736a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } 1737985f838934510983d8a887461e98dca60a6e858fJames Dong setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); 1738985f838934510983d8a887461e98dca60a6e858fJames Dong 1739d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 174020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1741ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 174293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 174320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 174493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 174520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 174620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 174720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 174813aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 174920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 175020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 175120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1752a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1753a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1754a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1755a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1756a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1757a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1758a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1759a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1760a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 176130ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 176230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 176303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 176403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 176503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1766548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1767548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 17681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 176903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 177003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 177103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 177203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1773be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 17741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 177503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 177603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 177703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 177803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 177903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 178003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 178130ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 178230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 178330ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 178430ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 178530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1786548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 178730ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 1788a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1789a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1790d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 1791d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 1792d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1793d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1794d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 1795d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 1796d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 1797d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 1798d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 1799d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 18001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 1801e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 1802b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong size_t sampleSize = copy->range_length(); 1803b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mIsAvc) { 1804b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1805b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 4; 1806b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1807b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 2; 1808b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1809b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1810050b28a593350047845a45a14cc5026221ac1620James Dong 1811d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 18121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes += sampleSize; 18131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong updateTrackSizeEstimate(); 18141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1815d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 1816d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1817d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1818d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1819d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 1820d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1821d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1822d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1823d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1824050b28a593350047845a45a14cc5026221ac1620James Dong 1825d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 1826d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1827d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 18288428af5381e835cc783b7ecb0d71cb60961c99c2James Dong /* 18298428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The original timestamp found in the data buffer will be modified as below: 18308428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18318428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * There is a playback offset into this track if the track's start time 18328428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is not the same as the movie start time, which will be recorded in edst 18338428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * box of the output file. The playback offset is to make sure that the 18348428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * starting time of the audio/video tracks are synchronized. Although the 18358428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * track's media timestamp may be subject to various modifications 18368428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * as outlined below, the track's playback offset time remains unchanged 18378428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * once the first data buffer of the track is received. 18388428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18398428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The media time stamp will be calculated by subtracting the playback offset 18408428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * (and potential pause durations) from the original timestamp in the buffer. 18418428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18428428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If this track is a video track for a real-time recording application with 18438428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * both audio and video tracks, its media timestamp will subject to further 18448428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * modification based on the media clock of the audio track. This modification 18458428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is needed for the purpose of maintaining good audio/video synchronization. 18468428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18478428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If the recording session is paused and resumed multiple times, the track 18488428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * media timestamp will be modified as if the recording session had never been 18498428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * paused at all during playback of the recorded output file. In other words, 18508428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * the output file will have no memory of pause/resume durations. 18518428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18528428af5381e835cc783b7ecb0d71cb60961c99c2James Dong */ 1853d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 18548428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs); 1855d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1856d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 18578644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 1858f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 1859f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 18608428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs = mStartTimestampUs; 18613c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 186248c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 1863a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 18648428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 18658428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(durExcludingEarlierPausesUs >= 0); 18668428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 18678428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(pausedDurationUs >= lastDurationUs); 18688428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs += pausedDurationUs - lastDurationUs; 1869a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 1870a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1871a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1872a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 18738428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(timestampUs >= 0); 1874872a481558350634a3fd5cb67939de288af00ecbJames Dong 1875872a481558350634a3fd5cb67939de288af00ecbJames Dong // Media time adjustment for real-time applications 1876872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsRealTimeRecording) { 1877872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 1878872a481558350634a3fd5cb67939de288af00ecbJames Dong updateDriftTime(meta_data); 1879872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1880872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustMediaTime(×tampUs); 1881e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1882e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1883872a481558350634a3fd5cb67939de288af00ecbJames Dong 1884e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 1885e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1886e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 18874f86a980fee1880dca61b828599fa6d76755a485James Dong LOGW("Frame arrives too late!"); 18884f86a980fee1880dca61b828599fa6d76755a485James Dong // Don't drop the late frame, since dropping a frame may cause 18894f86a980fee1880dca61b828599fa6d76755a485James Dong // problems later during playback 18904f86a980fee1880dca61b828599fa6d76755a485James Dong 18914f86a980fee1880dca61b828599fa6d76755a485James Dong // The idea here is to avoid having two or more samples with the 18924f86a980fee1880dca61b828599fa6d76755a485James Dong // same timestamp in the output file. 18934f86a980fee1880dca61b828599fa6d76755a485James Dong if (mTimeScale >= 1000000LL) { 189440e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + 1; 18954f86a980fee1880dca61b828599fa6d76755a485James Dong } else { 189640e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale; 18974f86a980fee1880dca61b828599fa6d76755a485James Dong } 1898e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1899e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1900e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 19018428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s media time stamp: %lld and previous paused duration %lld", 19028428af5381e835cc783b7ecb0d71cb60961c99c2James Dong mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); 1903c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 1904c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 19053b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 19063b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 19078644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 1908ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 1909ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 1910c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 1911c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 1912c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 1913c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 1914c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 1915c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 1916c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 1917c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 1918c059860c73678a202bfa33062723e8f82fb779d9James Dong 1919c059860c73678a202bfa33062723e8f82fb779d9James Dong if (currDurationTicks != lastDurationTicks) { 19201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 1921be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 1922be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1923be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 1924be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1925be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1926be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1927ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 1928be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 1929be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 19308644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 1931be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 19328644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 1933c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 19348644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 193520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1936d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 19371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStssTableEntry(mNumSamples); 1938d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 1939d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 194093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 194193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 194293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 194393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 1944faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 194593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 194658ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 1947c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 194858ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 194958ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 19501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addChunkOffset(offset); 195158ae9c530247668f8af36e30d228c716c226b3d4James Dong } 195258ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 195358ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 195458ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 195558ae9c530247668f8af36e30d228c716c226b3d4James Dong } 195613aec890216948b0c364f8f92792129d0335f506James Dong 195713aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 195813aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 19591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, 1); 19601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 196113aec890216948b0c364f8f92792129d0335f506James Dong } else { 196213aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 196313aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 196413aec890216948b0c364f8f92792129d0335f506James Dong } else { 196513aec890216948b0c364f8f92792129d0335f506James Dong if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 196613aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 196713aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 196813aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 196913aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 19701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(nChunks, mChunkSamples.size()); 197113aec890216948b0c364f8f92792129d0335f506James Dong } 19721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 197313aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 197413aec890216948b0c364f8f92792129d0335f506James Dong } 197513aec890216948b0c364f8f92792129d0335f506James Dong } 197613aec890216948b0c364f8f92792129d0335f506James Dong } 197713aec890216948b0c364f8f92792129d0335f506James Dong 197820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 197925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 1980a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong if (mSampleSizes.empty() || // no samples written 1981a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (!mIsAudio && mNumStssTableEntries == 0) || // no sync frames for video 1982a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (OK != checkCodecSpecificData())) { // no codec specific data 1983690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 1984f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 1985faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, -1, err); 1986be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 198713aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 198858ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 19891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(1, mNumSamples); 199058ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 19911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, mChunkSamples.size()); 19921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 199313aec890216948b0c364f8f92792129d0335f506James Dong } 199413aec890216948b0c364f8f92792129d0335f506James Dong 1995be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 1996be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 1997be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 1998ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 19998f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 2000be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2001be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 2002be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 20031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 2004c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 200525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 20061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 20071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video"); 2008872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2009872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); 2010872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2011365a963142093a1cd8efdcea76b5f65096a5b115James Dong 201237187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 201337187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 201437187916a486504acaf83bea30147eb5fbf46ae5James Dong } 201537187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 2016365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 2017365a963142093a1cd8efdcea76b5f65096a5b115James Dong 2018faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2019faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 2020215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 2021215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 202293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 2023faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err); 202493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 202593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 202693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 202793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 2028faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 2029faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong const MPEG4Writer::Track* track, int64_t timeUs, status_t err) { 2030faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 2031faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t nTracks = mTracks.size(); 2032faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks >= 1); 2033faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks < 64); // Arbitrary number 2034faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2035faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t trackNum = 0; 2036faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(trackNum < nTracks); 2037faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum <<= 16; 2038faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2039faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 2040faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 2041faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 2042faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_ERROR, 2043faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_ERROR_UNKNOWN, 2044faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2045faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2046faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2047faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2048faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 2049faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 2050faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 2051faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS, 2052faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2053faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2054faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 2055faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 2056faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 2057faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, 2058faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 2059faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2060faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 2061faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2062d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2063d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong LOGV("setDriftTimeUs: %lld us", driftTimeUs); 2064e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2065d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 2066e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2067e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2068e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 2069e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 2070e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2071e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 2072e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2073e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2074b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() { 2075b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong return mUse4ByteNalLength; 2076b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong} 2077b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 20781c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 20791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 20801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 20811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 20821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 208313aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 208420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 208520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 20863b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 2087c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 208820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 208920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2090d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2091d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 2092d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 2093d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2094690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 2095690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 2096690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2097690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2098690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2099690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2100690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 2101690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 2102a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Missing codec specific data"); 2103690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2104690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2105690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 2106690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 2107690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 2108a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Unexepected codec specific data found"); 2109690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2110690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2111690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2112690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 2113690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 2114690f546b0ee548dbfe997df36418e5302ec2d786James Dong 21151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader( 21161acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t trackID, bool use32BitOffset) { 211720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 211820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 21190c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 212020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 21221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 21238f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 212420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 21258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 21268f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 212720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 212820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 212920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 213020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 21311acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Flags = 7 to indicate that the track is enabled, and 21321acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // part of the presentation 21331acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x07); // version=0, flags=7 213420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 213520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 213620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 213720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 21388f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t tkhdDuration = 21398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 21408f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 214120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 214220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 214320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 214420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 21451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 214620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 214720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 214813f6284305e4b27395a23db7882d670bdb1bcae1James Dong mOwner->writeCompositionMatrix(mRotation); // matrix 214920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 215120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 215220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 215320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 215420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 215520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 215620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 21570c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 215820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2159050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2160050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 216120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 216220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 216320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2164f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 2165f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong if (mStartTimestampUs != moovStartTimeUs) { 21663c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("edts"); 21673c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("elst"); 21681acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 21691acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(2); // never ends with an empty list 21708f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 21718f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // First elst entry: specify the starting time offset 21728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; 21738428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("OffsetUs: %lld", offsetUs); 21748f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; 21758f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timecale 21768f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(-1); // starting time offset 21778f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(1 << 16); // rate = 1.0 21788f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 21798f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // Second elst entry: specify the track duration 21808f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 21818f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timescale 21821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); 21831acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); 21843c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 21853c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 21863c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 21873c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 218820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 218920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 219020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 219120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 219220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 219320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 21948f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mTimeScale); // media timescale 21958f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 21968f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mdhdDuration); // use media timescale 21971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Language follows the three letter standard ISO-639-2/T 21981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // 'e', 'n', 'g' for "English", for instance. 21991acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Each character is packed as the difference between its ASCII value and 0x60. 22001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // For "English", these are 00101, 01110, 00111. 22011acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // XXX: Where is the padding bit located: 0x15C7? 22021acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(0); // language code 220320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 220420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 220520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 220620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 220720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2208050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // component type: should be mhlr 22091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 221020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 221120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 221220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 22131acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Removing "r" for the name string just makes the string 4 byte aligned 22141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 221520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 221620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 221720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 22181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 221920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 222020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 222120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 222220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 222320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 222420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 222520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 22261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x01); // version=0, flags=1 222720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 222820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 222920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 223020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 223120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 223220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 2233050b28a593350047845a45a14cc5026221ac1620James Dong 2234050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dinf"); 2235050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dref"); 2236050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 22371acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // entry count (either url or urn) 22381acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // The table index here refers to the sample description index 22391acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // in the sample table entries. 2240050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("url "); 22411acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2242050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // url 2243050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dref 2244050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dinf 2245050b28a593350047845a45a14cc5026221ac1620James Dong 224620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 224720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 224820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 224920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 225020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 22511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 225225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 225318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 225425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 225518291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 225625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 2257050b28a593350047845a45a14cc5026221ac1620James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2258050b28a593350047845a45a14cc5026221ac1620James Dong fourcc = "mp4a"; 225925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 226025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 226125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 226225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 226325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 226425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 226520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 226620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 2267050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x1); // data ref index 226820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 226920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 2270050b28a593350047845a45a14cc5026221ac1620James Dong int32_t nChannels; 2271050b28a593350047845a45a14cc5026221ac1620James Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2272050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(nChannels); // channel count 227320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 227420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 227520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 227620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 227720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 227820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 22790c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 228020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 2281050b28a593350047845a45a14cc5026221ac1620James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2282050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("esds"); 228351dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 228451dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 2285050b28a593350047845a45a14cc5026221ac1620James Dong 22865f995b0e72ed6f186cb0ab2a525c4cfce614f3a9Andreas Huber // Make sure all sizes encode to a single byte. 22875f995b0e72ed6f186cb0ab2a525c4cfce614f3a9Andreas Huber CHECK(mCodecSpecificDataSize + 23 < 128); 22885f995b0e72ed6f186cb0ab2a525c4cfce614f3a9Andreas Huber 2289050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2290050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x03); // ES_DescrTag 2291050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2292050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x0000);// ES_ID 2293050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); 2294050b28a593350047845a45a14cc5026221ac1620James Dong 2295050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2296050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2297050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2298050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x15); // streamType AudioStream 2299050b28a593350047845a45a14cc5026221ac1620James Dong 2300050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x03); // XXX 2301050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2302050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // max bit rate 2303050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // avg bit rate 2304050b28a593350047845a45a14cc5026221ac1620James Dong 2305050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2306050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(mCodecSpecificDataSize); 2307050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2308050b28a593350047845a45a14cc5026221ac1620James Dong 2309050b28a593350047845a45a14cc5026221ac1620James Dong static const uint8_t kData2[] = { 2310050b28a593350047845a45a14cc5026221ac1620James Dong 0x06, // SLConfigDescriptorTag 2311050b28a593350047845a45a14cc5026221ac1620James Dong 0x01, 2312050b28a593350047845a45a14cc5026221ac1620James Dong 0x02 2313050b28a593350047845a45a14cc5026221ac1620James Dong }; 2314050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(kData2, sizeof(kData2)); 2315050b28a593350047845a45a14cc5026221ac1620James Dong 2316050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // esds 23175aff464f67322cd13dc8ed165806971cfff2e4d5James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 23185aff464f67322cd13dc8ed165806971cfff2e4d5James Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 23195aff464f67322cd13dc8ed165806971cfff2e4d5James Dong // 3gpp2 Spec AMRSampleEntry fields 23205aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->beginBox("damr"); 23215aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeCString(" "); // vendor: 4 bytes 23225aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // decoder version 23235aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 23245aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // mode change period 23255aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(1); // frames per sample 23265aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->endBox(); 2327050b28a593350047845a45a14cc5026221ac1620James Dong } 232820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 232920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 233018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 233120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 233218291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 233320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 233430ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 233530ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 233620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 233725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 23380c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 233920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 234020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 234120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 234220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 23431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(1); // data ref index 234420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 234520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 234620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 234720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 234820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 234920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 235020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 235120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 235220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 23530c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 235420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 235520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 235620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 235720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 235820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 235920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 236020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 236120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 236220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 236320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 236420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 23650c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 236620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 236718291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2368a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificData); 2369a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificDataSize > 0); 237020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 237120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 237220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 237320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 237420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 237520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 237620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 237720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 237820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 237920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 238020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 238120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 238220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 238320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 238420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 238520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 238620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 238720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 238820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 238920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 2390050b28a593350047845a45a14cc5026221ac1620James Dong 239120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 239220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 239320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 239420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 239520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 239620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 239720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 239820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 239920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 240020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 240120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 240220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 240320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 240418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 240520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 240620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 240720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 240820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 240920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 241020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 241120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 241220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 241330ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 241451dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 241595fcef25b48e35b625899288971ab628efbf8584Andreas Huber CHECK(mCodecSpecificDataSize >= 5); 241695fcef25b48e35b625899288971ab628efbf8584Andreas Huber 241795fcef25b48e35b625899288971ab628efbf8584Andreas Huber // Patch avcc's lengthSize field to match the number 241895fcef25b48e35b625899288971ab628efbf8584Andreas Huber // of bytes we use to indicate the size of a nal unit. 241995fcef25b48e35b625899288971ab628efbf8584Andreas Huber uint8_t *ptr = (uint8_t *)mCodecSpecificData; 242095fcef25b48e35b625899288971ab628efbf8584Andreas Huber ptr[4] = 242195fcef25b48e35b625899288971ab628efbf8584Andreas Huber (ptr[4] & 0xfc) 242295fcef25b48e35b625899288971ab628efbf8584Andreas Huber | (mOwner->useNalLengthFour() ? 3 : 1); 242395fcef25b48e35b625899288971ab628efbf8584Andreas Huber 242430ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 242530ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 242630ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 242720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 242830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 24291acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox("pasp"); 24301acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // This is useful if the pixel is not square 24311acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // hspacing 24321acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // vspacing 24331acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // pasp 243430ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 243520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 243620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 243720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 243820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 243920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 24401f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumSttsTableEntries); 2441c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t prevTimestampUs = 0; 2442be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 2443be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSttsTableEntries.end(); ++it) { 2444be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleCount); 2445c059860c73678a202bfa33062723e8f82fb779d9James Dong 2446c059860c73678a202bfa33062723e8f82fb779d9James Dong // Make sure that we are calculating the sample duration the exactly 2447c059860c73678a202bfa33062723e8f82fb779d9James Dong // same way as we made decision on how to create stts entries. 2448c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; 2449c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - 2450c059860c73678a202bfa33062723e8f82fb779d9James Dong (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2451c059860c73678a202bfa33062723e8f82fb779d9James Dong prevTimestampUs += (it->sampleCount * it->sampleDurationUs); 2452c059860c73678a202bfa33062723e8f82fb779d9James Dong 24538f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(dur); 245420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 245520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 245620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 24571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!mIsAudio) { 2458050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("stss"); 2459050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 24601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStssTableEntries); // number of sync frames 2461050b28a593350047845a45a14cc5026221ac1620James Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2462050b28a593350047845a45a14cc5026221ac1620James Dong it != mStssTableEntries.end(); ++it) { 2463050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(*it); 2464050b28a593350047845a45a14cc5026221ac1620James Dong } 2465050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // stss 2466050b28a593350047845a45a14cc5026221ac1620James Dong } 2467050b28a593350047845a45a14cc5026221ac1620James Dong 246820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 246920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2470be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 24718644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t>::iterator it = mSampleSizes.begin(); 24728644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); // default sample size 2473be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2474be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(0); 2475be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2476ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mOwner->writeInt32(mNumSamples); 2477be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (!mSamplesHaveSameSize) { 24788644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 24798644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 24808644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); 2481be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 248220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 248320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 248420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 248520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 248620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 24871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStscTableEntries); 248813aec890216948b0c364f8f92792129d0335f506James Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 248913aec890216948b0c364f8f92792129d0335f506James Dong it != mStscTableEntries.end(); ++it) { 249013aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->firstChunk); 249113aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->samplesPerChunk); 249213aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->sampleDescriptionId); 249320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 249420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 24951acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 249620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 24971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStcoTableEntries); 2498c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mChunkOffsets.begin(); 249913aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkOffsets.end(); ++it) { 25001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (use32BitOffset) { 25011acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 25021acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 25031acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt64((*it)); 25041acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 250520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 25068f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->endBox(); // stco or co64 250720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 250820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 25091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // minf 251020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 251120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 251220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 251320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 251420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2515