MPEG4Writer.cpp revision bc07bcc65e91c7aea9713631ae67760dcf1b0286
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: 55bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); 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; 81eaae38445a340c4857c1c5569475879a728e63b7James Dong volatile bool mStarted; 821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 85bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t mTrackId; 86c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 87e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 88e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // For realtime applications, we need to adjust the media clock 89e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // for video track based on the audio media clock 90e259531ce59ab1f31de5a23124b22536f6a5a767James Dong bool mIsRealTimeRecording; 91e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t mMaxTimeStampUs; 92d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t mMdatSizeBytes; 948f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 9520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 9720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 98ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // mNumSamples is used to track how many samples in mSampleSizes List. 99ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // This is to reduce the cost associated with mSampleSizes.size() call, 100ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // since it is O(n). Ideally, the fix should be in List class. 101ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong size_t mNumSamples; 1028644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t> mSampleSizes; 103be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 104be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 10513aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 1061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStcoTableEntries; 108c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong List<off64_t> mChunkOffsets; 10913aec890216948b0c364f8f92792129d0335f506James Dong 1101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStscTableEntries; 11113aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 11213aec890216948b0c364f8f92792129d0335f506James Dong 11313aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 11413aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 11513aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 11613aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 11713aec890216948b0c364f8f92792129d0335f506James Dong 11813aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 11913aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 12013aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 12113aec890216948b0c364f8f92792129d0335f506James Dong }; 12213aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 12320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumStssTableEntries; 125050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 126050b28a593350047845a45a14cc5026221ac1620James Dong 1271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t mNumSttsTableEntries; 128be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 129be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry(uint32_t count, uint32_t durationUs) 1318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong : sampleCount(count), sampleDurationUs(durationUs) {} 132be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 133be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 1348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong uint32_t sampleDurationUs; 135be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 136be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 137be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 1393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 1403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 1413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 1463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 1473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 1483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 15320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 154548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 15593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 15725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1583c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 15993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 16093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 16125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 162872a481558350634a3fd5cb67939de288af00ecbJames Dong // Has the media time adjustment for video started? 163872a481558350634a3fd5cb67939de288af00ecbJames Dong bool mIsMediaTimeAdjustmentOn; 164872a481558350634a3fd5cb67939de288af00ecbJames Dong // The time stamp when previous media time adjustment period starts 165872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustTimestampUs; 166872a481558350634a3fd5cb67939de288af00ecbJames Dong // Number of vidoe frames whose time stamp may be adjusted 167872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mMediaTimeAdjustNumFrames; 168872a481558350634a3fd5cb67939de288af00ecbJames Dong // The sample number when previous meida time adjustmnet period starts 169872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevMediaTimeAdjustSample; 170872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumulated drift time within a period of 171872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 172872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mTotalDriftTimeToAdjustUs; 173872a481558350634a3fd5cb67939de288af00ecbJames Dong // The total accumalated drift time since the start of the recording 174872a481558350634a3fd5cb67939de288af00ecbJames Dong // excluding the current time adjustment period 175872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t mPrevTotalAccumDriftTimeUs; 176872a481558350634a3fd5cb67939de288af00ecbJames Dong 177872a481558350634a3fd5cb67939de288af00ecbJames Dong // Update the audio track's drift information. 178872a481558350634a3fd5cb67939de288af00ecbJames Dong void updateDriftTime(const sp<MetaData>& meta); 179872a481558350634a3fd5cb67939de288af00ecbJames Dong 180872a481558350634a3fd5cb67939de288af00ecbJames Dong // Adjust the time stamp of the video track according to 181872a481558350634a3fd5cb67939de288af00ecbJames Dong // the drift time information from the audio track. 182872a481558350634a3fd5cb67939de288af00ecbJames Dong void adjustMediaTime(int64_t *timestampUs); 183872a481558350634a3fd5cb67939de288af00ecbJames Dong 18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 18537187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 18620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 1883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 1893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 19003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t makeAVCCodecSpecificData( 19103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size); 1923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t copyAVCCodecSpecificData( 1933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 1943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t parseAVCCodecSpecificData( 1953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 196215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 197215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 198faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 19993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 20003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 20119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 20219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 203c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 204c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 205c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 206c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 207c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 208c059860c73678a202bfa33062723e8f82fb779d9James Dong 209690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 210690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 21113f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t mRotation; 212690f546b0ee548dbfe997df36418e5302ec2d786James Dong 2131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void updateTrackSizeEstimate(); 2141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStscTableEntry(size_t chunkId, size_t sampleId); 2151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneStssTableEntry(size_t sampleId); 2161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs); 2171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 22020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 22120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 223674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(-1), 224674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(NO_INIT), 225b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 227a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 228a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 229a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 23020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 23113aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2327837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 233f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 234674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong 235674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC); 236674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mFd >= 0) { 237674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = OK; 238674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong } 23920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 24020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 24130ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 242674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong : mFd(dup(fd)), 243674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck(mFd < 0? NO_INIT: OK), 244b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength(true), 2451acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 246a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested(false), 247a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 248a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 24930ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 25013aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2517837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 252f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 25330ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 25430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 25520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 25620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 25720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong while (!mTracks.empty()) { 2591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong List<Track *>::iterator it = mTracks.begin(); 26020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 2611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong (*it) = NULL; 2621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mTracks.erase(it); 26320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 26420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 26520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 26620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 267dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 268dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 269dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 270dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 271dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 272dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 273dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 274dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 275dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 276dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 277dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 278dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 279dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 280dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 281dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 282dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 283dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 284dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 285dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) const { 286dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 287dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 288dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 289dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 290dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 291dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 292dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 293dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 294dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 295dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 296dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 297dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 2982dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 299bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Mutex::Autolock l(mLock); 300bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong if (mStarted) { 301bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong LOGE("Attempt to add source AFTER recording is started"); 302bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong return UNKNOWN_ERROR; 303bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong } 304bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong Track *track = new Track(this, source, mTracks.size()); 30520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 3062dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 3072dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 30820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 30920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 31093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 311a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 312a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 31393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 314a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 315a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 316a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 317a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 318a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 319a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 320a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 321a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 322a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 323a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 324a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 325a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 326a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3272dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 3282dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 3292dec2b5be2056c6d9428897dc672185872d30d17James Dong // 3302dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 3312dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 3322dec2b5be2056c6d9428897dc672185872d30d17James Dong 33378a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 3342dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 33578a1a286f736888ae7af8860b2c424af0d978848James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 3 3362dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 3372dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 3382dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 3392dec2b5be2056c6d9428897dc672185872d30d17James Dong 3402dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 3412dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 3422dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 34378a1a286f736888ae7af8860b2c424af0d978848James Dong static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 3442dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 3452dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 3462dec2b5be2056c6d9428897dc672185872d30d17James Dong 34778a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file size limit is set 348a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 34978a1a286f736888ae7af8860b2c424af0d978848James Dong size = mMaxFileSizeLimitBytes * 6 / 1000; 35078a1a286f736888ae7af8860b2c424af0d978848James Dong } 35178a1a286f736888ae7af8860b2c424af0d978848James Dong 35278a1a286f736888ae7af8860b2c424af0d978848James Dong // Max file duration limit is set 35378a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileDurationLimitUs != 0) { 35478a1a286f736888ae7af8860b2c424af0d978848James Dong if (bitRate > 0) { 35578a1a286f736888ae7af8860b2c424af0d978848James Dong int64_t size2 = 35678a1a286f736888ae7af8860b2c424af0d978848James Dong ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 35778a1a286f736888ae7af8860b2c424af0d978848James Dong if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 35878a1a286f736888ae7af8860b2c424af0d978848James Dong // When both file size and duration limits are set, 35978a1a286f736888ae7af8860b2c424af0d978848James Dong // we use the smaller limit of the two. 36078a1a286f736888ae7af8860b2c424af0d978848James Dong if (size > size2) { 36178a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 36278a1a286f736888ae7af8860b2c424af0d978848James Dong } 36378a1a286f736888ae7af8860b2c424af0d978848James Dong } else { 36478a1a286f736888ae7af8860b2c424af0d978848James Dong // Only max file duration limit is set 36578a1a286f736888ae7af8860b2c424af0d978848James Dong size = size2; 36678a1a286f736888ae7af8860b2c424af0d978848James Dong } 3672dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3682dec2b5be2056c6d9428897dc672185872d30d17James Dong } 36978a1a286f736888ae7af8860b2c424af0d978848James Dong 3702dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 3712dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 3722dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3732dec2b5be2056c6d9428897dc672185872d30d17James Dong 3742dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 3752dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 3762dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 3772dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 3782dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3792dec2b5be2056c6d9428897dc672185872d30d17James Dong 380a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 3812dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 3822dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 3832dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 3842dec2b5be2056c6d9428897dc672185872d30d17James Dong} 3852dec2b5be2056c6d9428897dc672185872d30d17James Dong 3862dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 387674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 38825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 38920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 39020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 391a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong /* 392a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * Check mMaxFileSizeLimitBytes at the beginning 393a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * since mMaxFileSizeLimitBytes may be implicitly 394a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * changed later for 32-bit file offset even if 395a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong * user does not ask to set it explicitly. 396a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong */ 397a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong if (mMaxFileSizeLimitBytes != 0) { 398a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong mIsFileSizeLimitExplicitlyRequested = true; 399a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong } 400a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong 4012dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 4022dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 4032dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 4042dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 4052dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 4062dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4072dec2b5be2056c6d9428897dc672185872d30d17James Dong 4081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mUse32BitOffset) { 4091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // Implicit 32 bit file size limit 4101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes == 0) { 4111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 4141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // If file size is set to be larger than the 32 bit file 4151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong // size limit, treat it as an error. 4161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 417872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGW("32-bit file size limit (%lld bytes) too big. " 418d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong "It is changed to %lld bytes", 419d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes, kMax32BitFileSize); 420d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong mMaxFileSizeLimitBytes = kMax32BitFileSize; 4211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong } 4231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 424b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong int32_t use2ByteNalLength; 425b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (param && 426b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 427b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong use2ByteNalLength) { 428b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mUse4ByteNalLength = false; 4292dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4302dec2b5be2056c6d9428897dc672185872d30d17James Dong 431065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 43293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 433a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 434a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 435a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 43693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 437a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 438a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 439a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 440a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 4418f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 4428f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 4438f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 4448f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 4458f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 4468f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 4478f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 4487837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 4497837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 4507837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 4517837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4527837c17063a4c50bc856ba59418516fdab731de7James Dong 45320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 45493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 45593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int32_t fileType; 45693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (param && param->findInt32(kKeyFileType, &fileType) && 45793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong fileType != OUTPUT_FORMAT_MPEG_4) { 45893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 45993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } else { 46093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("isom"); 46193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 46293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 46320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 46420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 46593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 46620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 46720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4687837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 46920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4707837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 4712dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 4722dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 4732dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 4742dec2b5be2056c6d9428897dc672185872d30d17James Dong } 4752dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 4767837c17063a4c50bc856ba59418516fdab731de7James Dong } 4777837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 478c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 4797837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 4807837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 4817837c17063a4c50bc856ba59418516fdab731de7James Dong 4827837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 4837837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 484c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 4851acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 4861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 4871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 4881acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 4891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 4901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 4921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 4931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 4941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 4951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 497a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 498a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 49920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 5001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 501a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 50225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 50320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 50420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const { 5061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong return mUse32BitOffset; 5071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 5081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 50937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 510674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 51137187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 512a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 513a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 51437187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 515a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 516a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 51737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 51837187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 51937187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 52037187916a486504acaf83bea30147eb5fbf46ae5James Dong } 521a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 52237187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 523a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 524a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 5251c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 526cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping writer thread"); 5271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 5291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 5301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 5321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 5331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 5341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 5351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 5361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 537cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Writer thread stopped"); 5381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 5391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 54013f6284305e4b27395a23db7882d670bdb1bcae1James Dong/* 54113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix: 54213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a b u | 54313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c d v | 54413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x y w | 54513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * 54613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following 54713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w}, 54813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while 54913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format. 55013f6284305e4b27395a23db7882d670bdb1bcae1James Dong */ 55113f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) { 55213f6284305e4b27395a23db7882d670bdb1bcae1James Dong LOGV("writeCompositionMatrix"); 55313f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t a = 0x00010000; 55413f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t b = 0; 55513f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t c = 0; 55613f6284305e4b27395a23db7882d670bdb1bcae1James Dong uint32_t d = 0x00010000; 55713f6284305e4b27395a23db7882d670bdb1bcae1James Dong switch (degrees) { 55813f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 0: 55913f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 56013f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 90: 56113f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 56213f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0x00010000; 56313f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0xFFFF0000; 56413f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 56513f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 56613f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 180: 56713f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0xFFFF0000; 56813f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0xFFFF0000; 56913f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 57013f6284305e4b27395a23db7882d670bdb1bcae1James Dong case 270: 57113f6284305e4b27395a23db7882d670bdb1bcae1James Dong a = 0; 57213f6284305e4b27395a23db7882d670bdb1bcae1James Dong b = 0xFFFF0000; 57313f6284305e4b27395a23db7882d670bdb1bcae1James Dong c = 0x00010000; 57413f6284305e4b27395a23db7882d670bdb1bcae1James Dong d = 0; 57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 57613f6284305e4b27395a23db7882d670bdb1bcae1James Dong default: 57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong CHECK(!"Should never reach this unknown rotation"); 57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong break; 57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong 58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(a); // a 58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(b); // b 58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // u 58413f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(c); // c 58513f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(d); // d 58613f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // v 58713f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // x 58813f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0); // y 58913f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeInt32(0x40000000); // w 59013f6284305e4b27395a23db7882d670bdb1bcae1James Dong} 59113f6284305e4b27395a23db7882d670bdb1bcae1James Dong 59213f6284305e4b27395a23db7882d670bdb1bcae1James Dong 59337187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() { 594674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong if (mInitCheck != OK) { 59537187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 59620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 59720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 59837187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 5998f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 60065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong int64_t minDurationUs = 0x7fffffffffffffffLL; 60120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 60220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 60337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 60437187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 60537187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 60637187916a486504acaf83bea30147eb5fbf46ae5James Dong } 60720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6088f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 6098f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 6108f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 61120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 61265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (durationUs < minDurationUs) { 61365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs = durationUs; 61465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 61565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong } 61665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong 61765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong if (mTracks.size() > 1) { 61865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong LOGD("Duration from tracks range is [%lld, %lld] us", 61965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong minDurationUs, maxDurationUs); 62020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 62120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 6237837c17063a4c50bc856ba59418516fdab731de7James Dong 62437187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 62537187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 626674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 627674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 628674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 62937187916a486504acaf83bea30147eb5fbf46ae5James Dong mStarted = false; 63037187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 63137187916a486504acaf83bea30147eb5fbf46ae5James Dong } 63237187916a486504acaf83bea30147eb5fbf46ae5James Dong 63320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 6341acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 635c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset, SEEK_SET); 6361acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 637c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 4); 6381acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 639c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mMdatOffset + 8, SEEK_SET); 6401acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 6411acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 642c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &size, 8); 6431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 644c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 647c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong const off64_t moovOffset = mOffset; 6487837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 6497837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 6507837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6517837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 652c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6; 65320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 65520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 65720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 65820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 6608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong writeInt32(mTimeScale); // mvhd timescale 6611acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(duration); 6621acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(0x10000); // rate: 1.0 66320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 66420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 66520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 66713f6284305e4b27395a23db7882d670bdb1bcae1James Dong writeCompositionMatrix(0); // matrix 66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 66920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 67020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 67220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 67420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 67520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 67620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 67720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 67820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 67920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 6801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong (*it)->writeTrackHeader(id, mUse32BitOffset); 68120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 68220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 68320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6847837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6857837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 6867837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 6877837c17063a4c50bc856ba59418516fdab731de7James Dong 6887837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 689c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mFreeBoxOffset, SEEK_SET); 6907837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 691674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 6927837c17063a4c50bc856ba59418516fdab731de7James Dong 6937837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 694c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 6957837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 6967837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 6977837c17063a4c50bc856ba59418516fdab731de7James Dong 6987837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 6997837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 7007837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 7017837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 7022dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 7032dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 7047837c17063a4c50bc856ba59418516fdab731de7James Dong } 7057837c17063a4c50bc856ba59418516fdab731de7James Dong 7060c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 708674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong close(mFd); 709674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mFd = -1; 710674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong mInitCheck = NO_INIT; 711a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 71237187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 71320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 71420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71513aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 71613aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 71713aec890216948b0c364f8f92792129d0335f506James Dong return OK; 71813aec890216948b0c364f8f92792129d0335f506James Dong} 71913aec890216948b0c364f8f92792129d0335f506James Dong 72013aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 72113aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 72213aec890216948b0c364f8f92792129d0335f506James Dong} 72313aec890216948b0c364f8f92792129d0335f506James Dong 72413aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 72513aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 72613aec890216948b0c364f8f92792129d0335f506James Dong} 72720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 728c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 729c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 73020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 731c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 732c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 733c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong buffer->range_length()); 73420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 73520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 73620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 73720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 73820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 73920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 74003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 74103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 74203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 74303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 74403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 74503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 74603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 74703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 74803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 74903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 75003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 75103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 75203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 75303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 754c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 755c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t old_offset = mOffset; 75630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 75730ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 75803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 759b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mUse4ByteNalLength) { 760b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 24; 761c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 762b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 16) & 0xff; 763c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 764b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = (length >> 8) & 0xff; 765c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 766b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 767c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 768c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong 769c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, 770c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong (const uint8_t *)buffer->data() + buffer->range_offset(), 771c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong length); 772b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 773b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 4; 774b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 775b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong CHECK(length < 65536); 77630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 777b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong uint8_t x = length >> 8; 778c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 779b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong x = length & 0xff; 780c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, &x, 1); 781c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 782b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong mOffset += length + 2; 783b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 78430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 78530ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 78630ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 78730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 7887837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 789674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong const void *ptr, size_t size, size_t nmemb) { 7907837c17063a4c50bc856ba59418516fdab731de7James Dong 7917837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 7927837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 793674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // This happens only when we write the moov box at the end of 794674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong // recording, not for each output video/audio frame we receive. 795c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 7961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 797c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mBoxes.begin(); 7987837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 7997837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 8007837c17063a4c50bc856ba59418516fdab731de7James Dong } 801674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong lseek64(mFd, mOffset, SEEK_SET); 802674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 803674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 8047837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 8057837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 8067837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 8077837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 8087837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 8097837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 8107837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 8117837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 8127837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 8137837c17063a4c50bc856ba59418516fdab731de7James Dong } 8147837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 815674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong ::write(mFd, ptr, size * nmemb); 8167837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 8177837c17063a4c50bc856ba59418516fdab731de7James Dong } 8187837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 8197837c17063a4c50bc856ba59418516fdab731de7James Dong} 8207837c17063a4c50bc856ba59418516fdab731de7James Dong 82120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 8220c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 82320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8247837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 8257837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 82620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 82820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 82920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 83020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 8320c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 83320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 834c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = *--mBoxes.end(); 83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 83620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8377837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 8387837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 8397837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 8407837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 841c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, offset, SEEK_SET); 8427837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 8437837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 844c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong lseek64(mFd, mOffset, SEEK_SET); 8457837c17063a4c50bc856ba59418516fdab731de7James Dong } 84620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 84720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 849674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 1); 85020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 85320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 854674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 2); 85520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 85620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 85820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 859674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 4); 86020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 86120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 86220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 86320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 864674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(&x, 1, 8); 86520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 86620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 86720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 86820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 869674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, n + 1); 87020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 87120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 87220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 8730c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 874674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(s, 1, 4); 87520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 87620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 87720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 878674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong write(data, 1, size); 87920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 88020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 88178a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const { 88278a1a286f736888ae7af8860b2c424af0d978848James Dong return mStreamableFile; 88378a1a286f736888ae7af8860b2c424af0d978848James Dong} 88478a1a286f736888ae7af8860b2c424af0d978848James Dong 885d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 886d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 887d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 888d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 889d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 890d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 891956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 892d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 893d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 894d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 895d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 8961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 897acd234bba9f048971d66890009eeff9a8db94be3James Dong // Be conservative in the estimate: do not exceed 95% of 898acd234bba9f048971d66890009eeff9a8db94be3James Dong // the target file limit. For small target file size limit, though, 899acd234bba9f048971d66890009eeff9a8db94be3James Dong // this will not help. 900acd234bba9f048971d66890009eeff9a8db94be3James Dong return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 901d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 902d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 903d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 904d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 905d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 906d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 907d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 908d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 909d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 910d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 911d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 912d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 913d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 914d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 915d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 916d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 917d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 91825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 91925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 92025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 92125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 92225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 92325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 92425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 92525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 92625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 92725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 92825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 92925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 93025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 931f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 932f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 933f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 9343c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 935065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 936f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 937f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 9383c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 9393c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 9403c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 941f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 9423c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 9433c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 9443c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 9453c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 94658ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 94758ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 94858ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 94958ae9c530247668f8af36e30d228c716c226b3d4James Dong} 95058ae9c530247668f8af36e30d228c716c226b3d4James Dong 95120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 95220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 95320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 954bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) 95520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 95625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 95720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 95820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 959a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 960a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 961eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted(false), 962bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mTrackId(trackId), 963c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 964956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 965be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 96620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 96725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 968548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 96913f6284305e4b27395a23db7882d670bdb1bcae1James Dong mReachedEOS(false), 97013f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation(0) { 97119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 9728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 9731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 9741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 9751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 9761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 9771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 9781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 9791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 980c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 981c059860c73678a202bfa33062723e8f82fb779d9James Dong} 982c059860c73678a202bfa33062723e8f82fb779d9James Dong 9831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() { 9841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset() 9861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ? mNumStcoTableEntries * 4 9871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong : mNumStcoTableEntries * 8; 9881f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 9891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4); 9901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 99178a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 99278a1a286f736888ae7af8860b2c424af0d978848James Dong if (!mOwner->isFileStreamable()) { 99378a1a286f736888ae7af8860b2c424af0d978848James Dong // Reserved free space is not large enough to hold 99478a1a286f736888ae7af8860b2c424af0d978848James Dong // all meta data and thus wasted. 99578a1a286f736888ae7af8860b2c424af0d978848James Dong mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 + // stsc box size 99678a1a286f736888ae7af8860b2c424af0d978848James Dong mNumStssTableEntries * 4 + // stss box size 99778a1a286f736888ae7af8860b2c424af0d978848James Dong mNumSttsTableEntries * 8 + // stts box size 99878a1a286f736888ae7af8860b2c424af0d978848James Dong stcoBoxSizeBytes + // stco box size 99978a1a286f736888ae7af8860b2c424af0d978848James Dong stszBoxSizeBytes; // stsz box size 100078a1a286f736888ae7af8860b2c424af0d978848James Dong } 10011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 10021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 10031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry( 10041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t chunkId, size_t sampleId) { 10051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 10061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong StscTableEntry stscEntry(chunkId, sampleId, 1); 10071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStscTableEntries.push_back(stscEntry); 10081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStscTableEntries; 10091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 10101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 10111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 10121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mStssTableEntries.push_back(sampleId); 10131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStssTableEntries; 10141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 10151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 10161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry( 10171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong size_t sampleCount, int64_t durationUs) { 10181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 10191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong SttsTableEntry sttsEntry(sampleCount, durationUs); 10201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mSttsTableEntries.push_back(sttsEntry); 10211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumSttsTableEntries; 10221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 10231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1024c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) { 10251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong ++mNumStcoTableEntries; 10261f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mChunkOffsets.push_back(offset); 10271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong} 10281f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1029c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 1030c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 1031c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 1032c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 1033c059860c73678a202bfa33062723e8f82fb779d9James Dong 1034c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 1035c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 1036c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 1037c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1038c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 1039c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 1040c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1041c059860c73678a202bfa33062723e8f82fb779d9James Dong 1042c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 1043c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 1044c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1045c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 1046c059860c73678a202bfa33062723e8f82fb779d9James Dong } 1047c059860c73678a202bfa33062723e8f82fb779d9James Dong 10488f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 104919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 105019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 105119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 105219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 105319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 105419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 105519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 105619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 105719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 105819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 105919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 106019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 106119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 106219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 106319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 106419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 106519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 106619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 106719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 106819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 106919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 107019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 107119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 107219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 107319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 107419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 107519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 107619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 107719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 107819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 107919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 108020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 108120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 108220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 108320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 108420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 108520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 108620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 108720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 108820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 108920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 109020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 109193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 109293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 109393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 109493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 109593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 109693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 109793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 109893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 109993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 110093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 110193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 110293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 110393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 110493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 110593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 11061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 11071c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 11081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 11091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 11101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 11111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 11121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11141c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 11151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 11161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 11171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 11181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 11211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 11231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 11241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 11251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 11261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 11301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1132fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) { 1133fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("writeChunkToFile: %lld from %s track", 1134fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video"); 1135fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1136fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong int32_t isFirstSample = true; 1137fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!chunk->mSamples.empty()) { 1138fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 1139fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1140fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong off64_t offset = chunk->mTrack->isAvc() 1141fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong ? addLengthPrefixedSample_l(*it) 1142fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong : addSample_l(*it); 1143fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1144fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (isFirstSample) { 1145fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mTrack->addChunkOffset(offset); 1146fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong isFirstSample = false; 11471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 11501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 1151fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.erase(it); 11521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1153fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong chunk->mSamples.clear(); 11541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1156fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() { 1157fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("writeAllChunks"); 11581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 11591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mChunkInfos.empty()) { 11601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!it->mChunks.empty()) { 1162fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Chunk chunk; 1163fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (findChunkToWrite(&chunk)) { 1164fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeChunkToFile(&chunk); 1165fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong ++outstandingChunks; 1166fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong } 11671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mTrack = NULL; 11691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.erase(it); 11701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 11721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 11731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 11741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1175fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 1176fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong LOGV("findChunkToWrite"); 11771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Find the smallest timestamp, and write that chunk out 11791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // XXX: What if some track is just too slow? 11801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 11811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 11821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 11831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 11841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 11851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 11861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 11871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 11881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 11891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 11941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 1195fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 11961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 11971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 11981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 11991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 12001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1201fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 12021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 12031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 12041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 1205fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong *chunk = *(it->mChunks.begin()); 1206fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong it->mChunks.erase(it->mChunks.begin()); 1207fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong CHECK_EQ(chunk->mTrack, track); 1208fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return true; 12091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1211fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1212fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong return false; 12131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12151c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 12161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 12171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1218a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 1219fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1220fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Mutex::Autolock autoLock(mLock); 12211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 1222fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong Chunk chunk; 1223fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong bool chunkFound = false; 1224fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1225fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 12261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 12271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 1229fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong // Actual write without holding the lock in order to 1230fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong // reduce the blocking time for media track threads. 1231fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong if (chunkFound) { 1232fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong mLock.unlock(); 1233fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeChunkToFile(&chunk); 1234fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong mLock.lock(); 1235fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong } 12361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 1237fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong 1238fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong writeAllChunks(); 12391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12411c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 12421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 12431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 12451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1246e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 12471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 12481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 12491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 12501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 12511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 12521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 12531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 12551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 12561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 12571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 12581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 12591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 12601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 12611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 12621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 126393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1264a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1265a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1266a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1267a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1268a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 126925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 127093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 127119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 127219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 127319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 127419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 127513f6284305e4b27395a23db7882d670bdb1bcae1James Dong int32_t rotationDegrees; 127613f6284305e4b27395a23db7882d670bdb1bcae1James Dong if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 127713f6284305e4b27395a23db7882d670bdb1bcae1James Dong mRotation = rotationDegrees; 127813f6284305e4b27395a23db7882d670bdb1bcae1James Dong } 127913f6284305e4b27395a23db7882d670bdb1bcae1James Dong 12805b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong mIsRealTimeRecording = true; 1281e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1282e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1283e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1284e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1285e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1286e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1287e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 128893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 128993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1290f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1291a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mIsRealTimeRecording && mOwner->numTracks() > 1) { 1292a472613aec322e25891abf5c77bf3f7e3c244920James Dong /* 1293a472613aec322e25891abf5c77bf3f7e3c244920James Dong * This extra delay of accepting incoming audio/video signals 1294a472613aec322e25891abf5c77bf3f7e3c244920James Dong * helps to align a/v start time at the beginning of a recording 1295a472613aec322e25891abf5c77bf3f7e3c244920James Dong * session, and it also helps eliminate the "recording" sound for 1296a472613aec322e25891abf5c77bf3f7e3c244920James Dong * camcorder applications. 1297a472613aec322e25891abf5c77bf3f7e3c244920James Dong * 1298a472613aec322e25891abf5c77bf3f7e3c244920James Dong * Ideally, this platform-specific value should be defined 1299a472613aec322e25891abf5c77bf3f7e3c244920James Dong * in media_profiles.xml file 1300a472613aec322e25891abf5c77bf3f7e3c244920James Dong */ 1301a472613aec322e25891abf5c77bf3f7e3c244920James Dong startTimeUs += 700000; 1302a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 1303a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1304f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1305a472613aec322e25891abf5c77bf3f7e3c244920James Dong 1306f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 130725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 130825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 130925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 131025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 131120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 131220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 131320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 131420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 131520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 131620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1317eaae38445a340c4857c1c5569475879a728e63b7James Dong mStarted = true; 1318c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 131925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1320956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 13211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStcoTableEntries = 0; 13221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStssTableEntries = 0; 13231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumStscTableEntries = 0; 13241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mNumSttsTableEntries = 0; 13251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes = 0; 1326872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = false; 1327872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = 0; 1328872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 0; 1329872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = 0; 1330872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 0; 1331872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = 0; 133220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 133325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 133420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 133525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 133625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 133720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 133820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 133937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1340a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 134137187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1342a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1343a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 134437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 1345cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track", mIsAudio? "Audio": "Video"); 1346eaae38445a340c4857c1c5569475879a728e63b7James Dong if (!mStarted) { 1347eaae38445a340c4857c1c5569475879a728e63b7James Dong LOGE("Stop() called but track is not started"); 1348eaae38445a340c4857c1c5569475879a728e63b7James Dong return ERROR_END_OF_STREAM; 1349eaae38445a340c4857c1c5569475879a728e63b7James Dong } 1350eaae38445a340c4857c1c5569475879a728e63b7James Dong 135120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 135237187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 135320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 135420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 135520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 135620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 135720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 135820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 135937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = (status_t) dummy; 136037187916a486504acaf83bea30147eb5fbf46ae5James Dong 1361cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("Stopping %s track source", mIsAudio? "Audio": "Video"); 136237187916a486504acaf83bea30147eb5fbf46ae5James Dong { 136337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = mSource->stop(); 136437187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { 136537187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 136637187916a486504acaf83bea30147eb5fbf46ae5James Dong } 136737187916a486504acaf83bea30147eb5fbf46ae5James Dong } 136837187916a486504acaf83bea30147eb5fbf46ae5James Dong 1369cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong LOGD("%s track stopped", mIsAudio? "Audio": "Video"); 137037187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 137120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 137220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 137325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 137425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 137525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 137625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 137720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 137820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 137920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 138020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 138137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 138237187916a486504acaf83bea30147eb5fbf46ae5James Dong return (void *) err; 138320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 138420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 13853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 13863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 13873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 13893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 13903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 13913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 13933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 13943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 13963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 13983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 13993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 14003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 14013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 14033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 14043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 14063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 14073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 14093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 14103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 14123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 14133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 14143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 14163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 14173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 14183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 14193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 14203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 14233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 14243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 14253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 14263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 14273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 14293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 14303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 14313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 14323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 14333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 14343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 14353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 14363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 14373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 14383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 14413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 14423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 14433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 14453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 14463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 14483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 14493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 14503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 14523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 14533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 14543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 14553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 14593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 14603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 14613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 14623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 14633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 14653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 14663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 14683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 14693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 14703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 14713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 14723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 14733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 14743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 14753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 14763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 14773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 14783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 14793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 14803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 14813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 14823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 14833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 14843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 14873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 14883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 14903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 14913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 14923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 14933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 14943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 14963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 14973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 14983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 14993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 15003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 15013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 15023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 15053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 15063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 15093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 15103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 15113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 15123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 15153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 15163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 15173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 15183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 15193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 15203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 15233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 15243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 15253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 15293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 15303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 15313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 15323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 15333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 15343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 15363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 15373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 15383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 15423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 15433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 15443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 15453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 15463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1553548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 155403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 155503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1556548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 155703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1558548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 155903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 156003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 156103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 15633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 156403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 156503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 156603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 15683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 15693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 157003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 157103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 157303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 157403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 157503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 15773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 157803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 157903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 15803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 15813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 15823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 15833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 158403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 1586b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1587b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 3; // length size == 4 bytes 1588b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1589b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong header[4] = 0xfc | 1; // length size == 2 bytes 1590b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 159103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 15923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 15933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 15943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 15953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 15963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 15973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 15983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 15993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 16003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 16013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 16023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 16043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 16053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 16063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 16073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 16093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 16103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 16113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 16123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 16133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 16143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 16153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 16163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 16173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 16183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 16193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 16203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 16213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 16223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 162303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 162403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 162503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 162603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 1627872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1628872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications 1629872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows: 1630872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1631872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of 1632872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs 1633872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of 1634872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small 1635872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value 1636872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding 1637872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep 1638872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the 1639872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is 1640872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track. 1641872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1642872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found 1643872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed 1644872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames 1645872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames 1646872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period. 1647872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion 1648872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames 1649872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is 1650872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media 1651872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a 1652872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5). 1653872a481558350634a3fd5cb67939de288af00ecbJames Dong* 1654872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that 1655872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift. 1656872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time 1657872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold 1658872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs. 1659872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental 1660872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the 1661872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift. 1662872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio 1663872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of 1664872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold 1665872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of 1666872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio 1667872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time 1668872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no 1669872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time 1670872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some 1671872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want 1672872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being. 1673872a481558350634a3fd5cb67939de288af00ecbJames Dong*/ 1674872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) { 1675872a481558350634a3fd5cb67939de288af00ecbJames Dong if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >= 1676872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs) { 1677872a481558350634a3fd5cb67939de288af00ecbJames Dong 1678872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("New media time adjustment period at %lld us", *timestampUs); 1679872a481558350634a3fd5cb67939de288af00ecbJames Dong mIsMediaTimeAdjustmentOn = true; 1680872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames = 1681872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample) >> 1; 1682872a481558350634a3fd5cb67939de288af00ecbJames Dong 1683872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustTimestampUs = *timestampUs; 1684872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevMediaTimeAdjustSample = mNumSamples; 1685872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs(); 1686872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs = 1687872a481558350634a3fd5cb67939de288af00ecbJames Dong totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs; 1688872a481558350634a3fd5cb67939de288af00ecbJames Dong 1689872a481558350634a3fd5cb67939de288af00ecbJames Dong mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs; 1690872a481558350634a3fd5cb67939de288af00ecbJames Dong 1691872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on incremental adjusted time per frame 1692872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t adjustTimePerFrameUs = 1693872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames; 1694872a481558350634a3fd5cb67939de288af00ecbJames Dong 1695872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs < 0) { 1696872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs = -adjustTimePerFrameUs; 1697872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1698872a481558350634a3fd5cb67939de288af00ecbJames Dong if (adjustTimePerFrameUs >= 5000) { 1699872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Adjusted time per video frame is %lld us", 1700872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustTimePerFrameUs); 1701872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"Video frame time adjustment is too large!"); 1702872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1703872a481558350634a3fd5cb67939de288af00ecbJames Dong 1704872a481558350634a3fd5cb67939de288af00ecbJames Dong // Check on total accumulated time drift within a period of 1705872a481558350634a3fd5cb67939de288af00ecbJames Dong // kVideoMediaTimeAdjustPeriodTimeUs. 1706872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000) 1707872a481558350634a3fd5cb67939de288af00ecbJames Dong / kVideoMediaTimeAdjustPeriodTimeUs; 1708872a481558350634a3fd5cb67939de288af00ecbJames Dong 1709872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage < 0) { 1710872a481558350634a3fd5cb67939de288af00ecbJames Dong driftPercentage = -driftPercentage; 1711872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1712872a481558350634a3fd5cb67939de288af00ecbJames Dong if (driftPercentage > 5) { 1713872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGE("Audio track has time drift %lld us over %lld us", 1714872a481558350634a3fd5cb67939de288af00ecbJames Dong mTotalDriftTimeToAdjustUs, 1715872a481558350634a3fd5cb67939de288af00ecbJames Dong kVideoMediaTimeAdjustPeriodTimeUs); 1716872a481558350634a3fd5cb67939de288af00ecbJames Dong 1717872a481558350634a3fd5cb67939de288af00ecbJames Dong CHECK(!"The audio track media time drifts too much!"); 1718872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1719872a481558350634a3fd5cb67939de288af00ecbJames Dong 1720872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1721872a481558350634a3fd5cb67939de288af00ecbJames Dong 1722872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsMediaTimeAdjustmentOn) { 1723872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mNumSamples - mPrevMediaTimeAdjustSample <= 1724872a481558350634a3fd5cb67939de288af00ecbJames Dong mMediaTimeAdjustNumFrames) { 1725872a481558350634a3fd5cb67939de288af00ecbJames Dong 1726872a481558350634a3fd5cb67939de288af00ecbJames Dong // Do media time incremental adjustment 1727872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t incrementalAdjustTimeUs = 1728872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs * 1729872a481558350634a3fd5cb67939de288af00ecbJames Dong (mNumSamples - mPrevMediaTimeAdjustSample)) 1730872a481558350634a3fd5cb67939de288af00ecbJames Dong / mMediaTimeAdjustNumFrames; 1731872a481558350634a3fd5cb67939de288af00ecbJames Dong 1732872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1733872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs); 1734872a481558350634a3fd5cb67939de288af00ecbJames Dong 1735872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Incremental video frame media time adjustment: %lld us", 1736872a481558350634a3fd5cb67939de288af00ecbJames Dong (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs)); 1737872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1738872a481558350634a3fd5cb67939de288af00ecbJames Dong // Within the remaining adjustment period, 1739872a481558350634a3fd5cb67939de288af00ecbJames Dong // no incremental adjustment is needed. 1740872a481558350634a3fd5cb67939de288af00ecbJames Dong *timestampUs += 1741872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs); 1742872a481558350634a3fd5cb67939de288af00ecbJames Dong 1743872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGV("Fixed video frame media time adjustment: %lld us", 1744872a481558350634a3fd5cb67939de288af00ecbJames Dong (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs)); 1745872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1746872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1747872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1748872a481558350634a3fd5cb67939de288af00ecbJames Dong 1749872a481558350634a3fd5cb67939de288af00ecbJames Dong/* 1750872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that 1751872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information 1752872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio 1753872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger 1754872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 1755872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined. 1756872a481558350634a3fd5cb67939de288af00ecbJames Dong */ 1757872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 1758872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t driftTimeUs = 0; 1759872a481558350634a3fd5cb67939de288af00ecbJames Dong if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 1760872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 1761872a481558350634a3fd5cb67939de288af00ecbJames Dong int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 1762872a481558350634a3fd5cb67939de288af00ecbJames Dong mOwner->setDriftTimeUs(timeUs); 1763872a481558350634a3fd5cb67939de288af00ecbJames Dong } 1764872a481558350634a3fd5cb67939de288af00ecbJames Dong} 1765872a481558350634a3fd5cb67939de288af00ecbJames Dong 176637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 176730ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 176813aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 176913aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 177013aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 177113aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 17728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 17738f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1774c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1775c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 17768f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1777be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1778a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 17791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1780e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1781a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong if (mIsAudio) { 1782a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 1783a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } else { 1784a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 1785a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong } 1786985f838934510983d8a887461e98dca60a6e858fJames Dong setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); 1787985f838934510983d8a887461e98dca60a6e858fJames Dong 1788d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 178920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1790ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 179193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 179220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 179393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 179420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 179520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 179620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 179713aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 179820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 179920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 180020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1801a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1802a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1803a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1804a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1805a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1806a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1807a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1808a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1809a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 181030ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 181130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 181203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 181303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 181403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1815548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1816548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 18171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 181803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 181903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 182003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 182103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1822be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 18231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 182403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 182503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 182603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 182703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 182803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 182903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 183030ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 183130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 183230ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 183330ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 183430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1835548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 183630ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 1837a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1838a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1839d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 1840d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 1841d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1842d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1843d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 1844d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 1845d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 1846d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 1847d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 1848d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 18491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 1850e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 1851b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong size_t sampleSize = copy->range_length(); 1852b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mIsAvc) { 1853b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong if (mOwner->useNalLengthFour()) { 1854b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 4; 1855b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } else { 1856b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong sampleSize += 2; 1857b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1858b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong } 1859050b28a593350047845a45a14cc5026221ac1620James Dong 1860d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 18611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mMdatSizeBytes += sampleSize; 18621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong updateTrackSizeEstimate(); 18631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong 1864d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 1865d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1866d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1867d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1868d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 1869d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1870d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1871d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1872d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1873050b28a593350047845a45a14cc5026221ac1620James Dong 1874d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 1875d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1876d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 18778428af5381e835cc783b7ecb0d71cb60961c99c2James Dong /* 18788428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The original timestamp found in the data buffer will be modified as below: 18798428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18808428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * There is a playback offset into this track if the track's start time 18818428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is not the same as the movie start time, which will be recorded in edst 18828428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * box of the output file. The playback offset is to make sure that the 18838428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * starting time of the audio/video tracks are synchronized. Although the 18848428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * track's media timestamp may be subject to various modifications 18858428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * as outlined below, the track's playback offset time remains unchanged 18868428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * once the first data buffer of the track is received. 18878428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18888428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * The media time stamp will be calculated by subtracting the playback offset 18898428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * (and potential pause durations) from the original timestamp in the buffer. 18908428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18918428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If this track is a video track for a real-time recording application with 18928428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * both audio and video tracks, its media timestamp will subject to further 18938428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * modification based on the media clock of the audio track. This modification 18948428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * is needed for the purpose of maintaining good audio/video synchronization. 18958428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 18968428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * If the recording session is paused and resumed multiple times, the track 18978428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * media timestamp will be modified as if the recording session had never been 18988428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * paused at all during playback of the recorded output file. In other words, 18998428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * the output file will have no memory of pause/resume durations. 19008428af5381e835cc783b7ecb0d71cb60961c99c2James Dong * 19018428af5381e835cc783b7ecb0d71cb60961c99c2James Dong */ 1902d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 19038428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs); 1904d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1905d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 19068644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 1907f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 1908f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 19098428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs = mStartTimestampUs; 19103c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 191148c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 1912a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 19138428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 19148428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(durExcludingEarlierPausesUs >= 0); 19158428af5381e835cc783b7ecb0d71cb60961c99c2James Dong int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 19168428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(pausedDurationUs >= lastDurationUs); 19178428af5381e835cc783b7ecb0d71cb60961c99c2James Dong previousPausedDurationUs += pausedDurationUs - lastDurationUs; 1918a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 1919a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1920a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1921a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 19228428af5381e835cc783b7ecb0d71cb60961c99c2James Dong CHECK(timestampUs >= 0); 1923872a481558350634a3fd5cb67939de288af00ecbJames Dong 1924872a481558350634a3fd5cb67939de288af00ecbJames Dong // Media time adjustment for real-time applications 1925872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsRealTimeRecording) { 1926872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 1927872a481558350634a3fd5cb67939de288af00ecbJames Dong updateDriftTime(meta_data); 1928872a481558350634a3fd5cb67939de288af00ecbJames Dong } else { 1929872a481558350634a3fd5cb67939de288af00ecbJames Dong adjustMediaTime(×tampUs); 1930e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1931e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1932872a481558350634a3fd5cb67939de288af00ecbJames Dong 1933e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 1934e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1935e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 19364f86a980fee1880dca61b828599fa6d76755a485James Dong LOGW("Frame arrives too late!"); 19374f86a980fee1880dca61b828599fa6d76755a485James Dong // Don't drop the late frame, since dropping a frame may cause 19384f86a980fee1880dca61b828599fa6d76755a485James Dong // problems later during playback 19394f86a980fee1880dca61b828599fa6d76755a485James Dong 19404f86a980fee1880dca61b828599fa6d76755a485James Dong // The idea here is to avoid having two or more samples with the 19414f86a980fee1880dca61b828599fa6d76755a485James Dong // same timestamp in the output file. 19424f86a980fee1880dca61b828599fa6d76755a485James Dong if (mTimeScale >= 1000000LL) { 194340e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + 1; 19444f86a980fee1880dca61b828599fa6d76755a485James Dong } else { 194540e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale; 19464f86a980fee1880dca61b828599fa6d76755a485James Dong } 1947e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1948e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1949e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 19508428af5381e835cc783b7ecb0d71cb60961c99c2James Dong LOGV("%s media time stamp: %lld and previous paused duration %lld", 19518428af5381e835cc783b7ecb0d71cb60961c99c2James Dong mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); 1952c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 1953c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 19543b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 19553b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 19568644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 1957ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 1958ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 1959c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 1960c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 1961c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 1962c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 1963c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 1964c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 1965c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 1966c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 1967c059860c73678a202bfa33062723e8f82fb779d9James Dong 1968a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Force the first sample to have its own stts entry so that 1969a472613aec322e25891abf5c77bf3f7e3c244920James Dong // we can adjust its value later to maintain the A/V sync. 1970a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) { 1971a472613aec322e25891abf5c77bf3f7e3c244920James Dong LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us", 1972a472613aec322e25891abf5c77bf3f7e3c244920James Dong mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks); 19731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 1974be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 1975be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1976be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 1977be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1978be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1979be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1980ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 1981be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 1982be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 19838644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 1984be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1985a472613aec322e25891abf5c77bf3f7e3c244920James Dong LOGV("%s timestampUs/lastTimestampUs: %lld/%lld", 1986a472613aec322e25891abf5c77bf3f7e3c244920James Dong mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs); 19878644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 1988c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 19898644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 199020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1991d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 19921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStssTableEntry(mNumSamples); 1993d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 1994d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 199593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 199693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 199793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 199893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 1999faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 200093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 200158ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 2002c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 200358ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 200458ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 20051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addChunkOffset(offset); 200658ae9c530247668f8af36e30d228c716c226b3d4James Dong } 200758ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 200858ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 200958ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 201058ae9c530247668f8af36e30d228c716c226b3d4James Dong } 201113aec890216948b0c364f8f92792129d0335f506James Dong 201213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 201313aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 20141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, 1); 20151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 201613aec890216948b0c364f8f92792129d0335f506James Dong } else { 201713aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 201813aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 201913aec890216948b0c364f8f92792129d0335f506James Dong } else { 202013aec890216948b0c364f8f92792129d0335f506James Dong if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 202113aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 202213aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 202313aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 202413aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 20251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(nChunks, mChunkSamples.size()); 202613aec890216948b0c364f8f92792129d0335f506James Dong } 20271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 202813aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 202913aec890216948b0c364f8f92792129d0335f506James Dong } 203013aec890216948b0c364f8f92792129d0335f506James Dong } 203113aec890216948b0c364f8f92792129d0335f506James Dong } 203213aec890216948b0c364f8f92792129d0335f506James Dong 203320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 203425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 2035a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong if (mSampleSizes.empty() || // no samples written 2036a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (!mIsAudio && mNumStssTableEntries == 0) || // no sync frames for video 2037a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong (OK != checkCodecSpecificData())) { // no codec specific data 2038690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 2039f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 2040bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, -1, err); 2041be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 204213aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 204358ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 20441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(1, mNumSamples); 204558ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 20461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong addOneStscTableEntry(++nChunks, mChunkSamples.size()); 20471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 204813aec890216948b0c364f8f92792129d0335f506James Dong } 204913aec890216948b0c364f8f92792129d0335f506James Dong 2050be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 2051be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 2052be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 2053ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 20548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 2055be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2056be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 2057be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2058a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2059a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (mNumSamples <= 2) { 2060a472613aec322e25891abf5c77bf3f7e3c244920James Dong addOneSttsTableEntry(1, lastDurationUs); 2061a472613aec322e25891abf5c77bf3f7e3c244920James Dong if (sampleCount - 1 > 0) { 2062a472613aec322e25891abf5c77bf3f7e3c244920James Dong addOneSttsTableEntry(sampleCount - 1, lastDurationUs); 2063a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2064a472613aec322e25891abf5c77bf3f7e3c244920James Dong } else { 2065a472613aec322e25891abf5c77bf3f7e3c244920James Dong addOneSttsTableEntry(sampleCount, lastDurationUs); 2066a472613aec322e25891abf5c77bf3f7e3c244920James Dong } 2067a472613aec322e25891abf5c77bf3f7e3c244920James Dong 2068c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 206925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 20701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 20711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video"); 2072872a481558350634a3fd5cb67939de288af00ecbJames Dong if (mIsAudio) { 2073872a481558350634a3fd5cb67939de288af00ecbJames Dong LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); 2074872a481558350634a3fd5cb67939de288af00ecbJames Dong } 2075365a963142093a1cd8efdcea76b5f65096a5b115James Dong 207637187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 207737187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 207837187916a486504acaf83bea30147eb5fbf46ae5James Dong } 207937187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 2080365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 2081365a963142093a1cd8efdcea76b5f65096a5b115James Dong 2082faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2083faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 2084215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 2085215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 208693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 2087bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 208893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 208993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 209093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 209193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 2092faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 2093bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong size_t trackId, int64_t timeUs, status_t err) { 2094faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 2095bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong int32_t trackNum = (trackId << 28); 2096faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2097faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 2098faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 2099faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 2100bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2101bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 2102faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2103faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 2104faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2105faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2106faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 2107faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 2108bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2109bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 2110faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 2111faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 2112faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 2113bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2114bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 2115faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 2116faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 2117faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 2118faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 2119d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2120d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong LOGV("setDriftTimeUs: %lld us", driftTimeUs); 2121e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2122d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 2123e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2124e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2125e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 2126e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 2127e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 2128e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 2129e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 2130e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 2131b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() { 2132b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong return mUse4ByteNalLength; 2133b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong} 2134b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong 21351c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 21361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 21371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 21381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 21391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 214013aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 214120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 214220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21433b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 2144c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 214520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 214620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2147d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2148d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 2149d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 2150d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 2151690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 2152690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 2153690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2154690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2155690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2156690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2157690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 2158690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 2159a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Missing codec specific data"); 2160690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2161690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2162690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 2163690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 2164690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 2165a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong LOGE("Unexepected codec specific data found"); 2166690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 2167690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2168690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 2169690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 2170690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 2171690f546b0ee548dbfe997df36418e5302ec2d786James Dong 21721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader( 21731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t trackID, bool use32BitOffset) { 217420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 217520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 21760c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 217720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21788f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 21791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 21808f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 218120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 21828f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 21838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 218420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2185a472613aec322e25891abf5c77bf3f7e3c244920James Dong // Compensate for small start time difference from different media tracks 2186a472613aec322e25891abf5c77bf3f7e3c244920James Dong int64_t trackStartTimeOffsetUs = 0; 2187a472613aec322e25891abf5c77bf3f7e3c244920James Dong 218820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 218920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 219020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 21911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Flags = 7 to indicate that the track is enabled, and 21921acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // part of the presentation 21931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x07); // version=0, flags=7 219420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 219520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 219620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 219720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 21988f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t tkhdDuration = 21998f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 22008f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 220120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 220220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 220320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 220420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 22051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 220620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 220720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 220813f6284305e4b27395a23db7882d670bdb1bcae1James Dong mOwner->writeCompositionMatrix(mRotation); // matrix 220920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 221120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 221220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 221320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 221420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 221520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 221620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 22170c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 221820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2219050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2220050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 222120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 222220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 222320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2224f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 2225f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong if (mStartTimestampUs != moovStartTimeUs) { 2226a472613aec322e25891abf5c77bf3f7e3c244920James Dong CHECK(mStartTimestampUs > moovStartTimeUs); 2227a472613aec322e25891abf5c77bf3f7e3c244920James Dong trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 22283c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 22293c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 223020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 223120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 223220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 223320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 223420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 223520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 22368f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mTimeScale); // media timescale 22378f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 22388f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mdhdDuration); // use media timescale 22391acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Language follows the three letter standard ISO-639-2/T 22401acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // 'e', 'n', 'g' for "English", for instance. 22411acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Each character is packed as the difference between its ASCII value and 0x60. 22421acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // For "English", these are 00101, 01110, 00111. 22431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // XXX: Where is the padding bit located: 0x15C7? 22441acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(0); // language code 224520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 224620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 224720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 224820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 224920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2250050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // component type: should be mhlr 22511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 225220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 225320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 225420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 22551acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Removing "r" for the name string just makes the string 4 byte aligned 22561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 225720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 225820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 225920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 22601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 226120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 226220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 226320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 226420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 226520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 226620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 226720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 22681acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x01); // version=0, flags=1 226920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 227020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 227120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 227220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 227320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 227420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 2275050b28a593350047845a45a14cc5026221ac1620James Dong 2276050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dinf"); 2277050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dref"); 2278050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 22791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // entry count (either url or urn) 22801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // The table index here refers to the sample description index 22811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // in the sample table entries. 2282050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("url "); 22831acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2284050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // url 2285050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dref 2286050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dinf 2287050b28a593350047845a45a14cc5026221ac1620James Dong 228820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 228920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 229020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 229120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 229220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 22931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 229425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 229518291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 229625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 229718291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 229825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 2299050b28a593350047845a45a14cc5026221ac1620James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2300050b28a593350047845a45a14cc5026221ac1620James Dong fourcc = "mp4a"; 230125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 230225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 230325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 230425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 230525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 230625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 230720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 230820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 2309050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x1); // data ref index 231020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 231120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 2312050b28a593350047845a45a14cc5026221ac1620James Dong int32_t nChannels; 2313050b28a593350047845a45a14cc5026221ac1620James Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2314050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(nChannels); // channel count 231520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 231620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 231720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 231820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 231920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 232020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 23210c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 232220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 2323050b28a593350047845a45a14cc5026221ac1620James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2324050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("esds"); 232551dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 232651dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 2327050b28a593350047845a45a14cc5026221ac1620James Dong 23285f995b0e72ed6f186cb0ab2a525c4cfce614f3a9Andreas Huber // Make sure all sizes encode to a single byte. 23295f995b0e72ed6f186cb0ab2a525c4cfce614f3a9Andreas Huber CHECK(mCodecSpecificDataSize + 23 < 128); 23305f995b0e72ed6f186cb0ab2a525c4cfce614f3a9Andreas Huber 2331050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2332050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x03); // ES_DescrTag 2333050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2334050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x0000);// ES_ID 2335050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); 2336050b28a593350047845a45a14cc5026221ac1620James Dong 2337050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2338050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2339050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2340050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x15); // streamType AudioStream 2341050b28a593350047845a45a14cc5026221ac1620James Dong 2342050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x03); // XXX 2343050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2344050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // max bit rate 2345050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // avg bit rate 2346050b28a593350047845a45a14cc5026221ac1620James Dong 2347050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2348050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(mCodecSpecificDataSize); 2349050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2350050b28a593350047845a45a14cc5026221ac1620James Dong 2351050b28a593350047845a45a14cc5026221ac1620James Dong static const uint8_t kData2[] = { 2352050b28a593350047845a45a14cc5026221ac1620James Dong 0x06, // SLConfigDescriptorTag 2353050b28a593350047845a45a14cc5026221ac1620James Dong 0x01, 2354050b28a593350047845a45a14cc5026221ac1620James Dong 0x02 2355050b28a593350047845a45a14cc5026221ac1620James Dong }; 2356050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(kData2, sizeof(kData2)); 2357050b28a593350047845a45a14cc5026221ac1620James Dong 2358050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // esds 23595aff464f67322cd13dc8ed165806971cfff2e4d5James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 23605aff464f67322cd13dc8ed165806971cfff2e4d5James Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 23615aff464f67322cd13dc8ed165806971cfff2e4d5James Dong // 3gpp2 Spec AMRSampleEntry fields 23625aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->beginBox("damr"); 23635aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeCString(" "); // vendor: 4 bytes 23645aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // decoder version 23655aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 23665aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // mode change period 23675aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(1); // frames per sample 23685aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->endBox(); 2369050b28a593350047845a45a14cc5026221ac1620James Dong } 237020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 237120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 237218291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 237320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 237418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 237520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 237630ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 237730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 237820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 237925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 23800c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 238120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 238220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 238320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 238420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 23851acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(1); // data ref index 238620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 238720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 238820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 238920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 239020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 239120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 239220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 239320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 239420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 23950c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 239620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 239720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 239820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 239920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 240020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 240120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 240220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 240320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 240420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 240520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 240620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 24070c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 240820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 240918291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2410a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificData); 2411a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificDataSize > 0); 241220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 241320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 241420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 241520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 241620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 241720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 241820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 241920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 242020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 242120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 242220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 242320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 242420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 242520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 242620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 242720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 242820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 242920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 243020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 243120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 2432050b28a593350047845a45a14cc5026221ac1620James Dong 243320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 243420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 243520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 243620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 243720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 243820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 243920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 244020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 244120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 244220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 244320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 244420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 244520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 244618291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 244720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 244820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 244920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 245020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 245120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 245220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 245320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 245420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 245530ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 245651dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 245795fcef25b48e35b625899288971ab628efbf8584Andreas Huber CHECK(mCodecSpecificDataSize >= 5); 245895fcef25b48e35b625899288971ab628efbf8584Andreas Huber 245995fcef25b48e35b625899288971ab628efbf8584Andreas Huber // Patch avcc's lengthSize field to match the number 246095fcef25b48e35b625899288971ab628efbf8584Andreas Huber // of bytes we use to indicate the size of a nal unit. 246195fcef25b48e35b625899288971ab628efbf8584Andreas Huber uint8_t *ptr = (uint8_t *)mCodecSpecificData; 246295fcef25b48e35b625899288971ab628efbf8584Andreas Huber ptr[4] = 246395fcef25b48e35b625899288971ab628efbf8584Andreas Huber (ptr[4] & 0xfc) 246495fcef25b48e35b625899288971ab628efbf8584Andreas Huber | (mOwner->useNalLengthFour() ? 3 : 1); 246595fcef25b48e35b625899288971ab628efbf8584Andreas Huber 246630ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 246730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 246830ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 246920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 247030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 24711acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox("pasp"); 24721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // This is useful if the pixel is not square 24731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // hspacing 24741acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // vspacing 24751acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // pasp 247630ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 247720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 247820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 247920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 248020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 248120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 24821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumSttsTableEntries); 2483a472613aec322e25891abf5c77bf3f7e3c244920James Dong int64_t prevTimestampUs = trackStartTimeOffsetUs; 2484be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 2485be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSttsTableEntries.end(); ++it) { 2486be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleCount); 2487c059860c73678a202bfa33062723e8f82fb779d9James Dong 2488c059860c73678a202bfa33062723e8f82fb779d9James Dong // Make sure that we are calculating the sample duration the exactly 2489c059860c73678a202bfa33062723e8f82fb779d9James Dong // same way as we made decision on how to create stts entries. 2490c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; 2491c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - 2492c059860c73678a202bfa33062723e8f82fb779d9James Dong (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2493c059860c73678a202bfa33062723e8f82fb779d9James Dong prevTimestampUs += (it->sampleCount * it->sampleDurationUs); 2494c059860c73678a202bfa33062723e8f82fb779d9James Dong 24958f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(dur); 249620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 249720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 249820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 24991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!mIsAudio) { 2500050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("stss"); 2501050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 25021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStssTableEntries); // number of sync frames 2503050b28a593350047845a45a14cc5026221ac1620James Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2504050b28a593350047845a45a14cc5026221ac1620James Dong it != mStssTableEntries.end(); ++it) { 2505050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(*it); 2506050b28a593350047845a45a14cc5026221ac1620James Dong } 2507050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // stss 2508050b28a593350047845a45a14cc5026221ac1620James Dong } 2509050b28a593350047845a45a14cc5026221ac1620James Dong 251020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 251120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2512be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 25138644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t>::iterator it = mSampleSizes.begin(); 25148644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); // default sample size 2515be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2516be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(0); 2517be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2518ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mOwner->writeInt32(mNumSamples); 2519be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (!mSamplesHaveSameSize) { 25208644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 25218644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 25228644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); 2523be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 252420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 252520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 252620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 252720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 252820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 25291f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStscTableEntries); 253013aec890216948b0c364f8f92792129d0335f506James Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 253113aec890216948b0c364f8f92792129d0335f506James Dong it != mStscTableEntries.end(); ++it) { 253213aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->firstChunk); 253313aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->samplesPerChunk); 253413aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->sampleDescriptionId); 253520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 253620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 25371acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 253820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 25391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong mOwner->writeInt32(mNumStcoTableEntries); 2540c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong for (List<off64_t>::iterator it = mChunkOffsets.begin(); 254113aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkOffsets.end(); ++it) { 25421acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (use32BitOffset) { 25431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 25441acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 25451acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt64((*it)); 25461acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 254720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 25488f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->endBox(); // stco or co64 254920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 255020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 25511acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // minf 255220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 255320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 255420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 255520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 255620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2557