MPEG4Writer.cpp revision 690f546b0ee548dbfe997df36418e5302ec2d786
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 <ctype.h> 2420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h> 2520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 290c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h> 3018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 3103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 34d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h> 35365a963142093a1cd8efdcea76b5f65096a5b115James Dong#include <cutils/properties.h> 3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 3819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 4625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track(MPEG4Writer *owner, const sp<MediaSource> &source); 478f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 4820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 4920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 5137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 5237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 5325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 553b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 56d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 571acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); 581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void addChunkOffset(off_t offset) { mChunkOffsets.push_back(offset); } 6320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 6520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 6620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 67693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 6820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 69a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 70a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 74c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 75e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 76e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // For realtime applications, we need to adjust the media clock 77e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // for video track based on the audio media clock 78e259531ce59ab1f31de5a23124b22536f6a5a767James Dong bool mIsRealTimeRecording; 79e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t mMaxTimeStampUs; 80d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t mMaxWriteTimeUs; 828f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 8320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 8520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 86ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // mNumSamples is used to track how many samples in mSampleSizes List. 87ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // This is to reduce the cost associated with mSampleSizes.size() call, 88ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // since it is O(n). Ideally, the fix should be in List class. 89ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong size_t mNumSamples; 908644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t> mSampleSizes; 91be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 92be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 9313aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 9413aec890216948b0c364f8f92792129d0335f506James Dong List<off_t> mChunkOffsets; 9513aec890216948b0c364f8f92792129d0335f506James Dong 9613aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 9713aec890216948b0c364f8f92792129d0335f506James Dong 9813aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 9913aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 10013aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 10113aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 10213aec890216948b0c364f8f92792129d0335f506James Dong 10313aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 10413aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 10513aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 10613aec890216948b0c364f8f92792129d0335f506James Dong }; 10713aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 10820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 109050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 110365a963142093a1cd8efdcea76b5f65096a5b115James Dong List<int64_t> mChunkDurations; 111050b28a593350047845a45a14cc5026221ac1620James Dong 112be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 113be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1148f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry(uint32_t count, uint32_t durationUs) 1158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong : sampleCount(count), sampleDurationUs(durationUs) {} 116be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 117be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 1188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong uint32_t sampleDurationUs; 119be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 120be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 121be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 1233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 1243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 1253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 1263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 1283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 1293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 1303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 1313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 1323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 1333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 1343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 1353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 13720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 138548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 13993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 14020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 14125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1423c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 14393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 14493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 14525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 14620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 14737187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 14820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t makeAVCCodecSpecificData( 15303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size); 1543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t copyAVCCodecSpecificData( 1553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 1563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t parseAVCCodecSpecificData( 1573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 158215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 159215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 160faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 16193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 16203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 163215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Utilities for collecting statistical data 164215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong void logStatisticalData(bool isAudio); 165215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong void findMinAvgMaxSampleDurationMs( 166215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t *min, int32_t *avg, int32_t *max); 167215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong void findMinMaxChunkDurations(int64_t *min, int64_t *max); 168215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 16919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 17019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 171c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 172c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 173c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 174c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 175c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 176c059860c73678a202bfa33062723e8f82fb779d9James Dong 177690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 178690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 179690f546b0ee548dbfe997df36418e5302ec2d786James Dong 18020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 18120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 18220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 18320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#define USE_NALLEN_FOUR 1 18503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 18620111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 18720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mFile(fopen(filename, "wb")), 1881acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 189a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 190a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 19120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 19213aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 1937837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 194f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 1950c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mFile != NULL); 19620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 19720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19830ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 19930ab66297501757d745b9ae10da61adcd891f497Andreas Huber : mFile(fdopen(fd, "wb")), 2001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 201a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 202a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 20330ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 20413aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2057837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 206f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 20730ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(mFile != NULL); 20830ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 20930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 21020111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 21120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 21220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 21420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 21520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 21620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 21720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2202dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 22125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track *track = new Track(this, source); 22220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 2232dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 2242dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 22520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 22620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 228a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 229a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 23093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 231a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 232a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 233a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 234a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 235a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 236a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 237a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 238a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 239a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 240a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 241a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 242a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 243a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2442dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 2452dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 2462dec2b5be2056c6d9428897dc672185872d30d17James Dong // 2472dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 2482dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 2492dec2b5be2056c6d9428897dc672185872d30d17James Dong // Currently, lets set to 0.4% for now. 2502dec2b5be2056c6d9428897dc672185872d30d17James Dong 2512dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB, 2522dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 2532dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 4 2542dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 2552dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 2562dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 2572dec2b5be2056c6d9428897dc672185872d30d17James Dong 2582dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 2592dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 2602dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 2612dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024; // 4 KB 2622dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 2632dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 2642dec2b5be2056c6d9428897dc672185872d30d17James Dong 2652dec2b5be2056c6d9428897dc672185872d30d17James Dong if (mMaxFileSizeLimitBytes != 0) { 2662dec2b5be2056c6d9428897dc672185872d30d17James Dong size = mMaxFileSizeLimitBytes * 4 / 1000; 2672dec2b5be2056c6d9428897dc672185872d30d17James Dong } else if (mMaxFileDurationLimitUs != 0) { 2682dec2b5be2056c6d9428897dc672185872d30d17James Dong if (bitRate <= 0) { 2692dec2b5be2056c6d9428897dc672185872d30d17James Dong // We could not estimate the file size since bitRate is not set. 2702dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 2712dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 2722dec2b5be2056c6d9428897dc672185872d30d17James Dong size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000); 2732dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2742dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2752dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 2762dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 2772dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2782dec2b5be2056c6d9428897dc672185872d30d17James Dong 2792dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 2802dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 2812dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 2822dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 2832dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2842dec2b5be2056c6d9428897dc672185872d30d17James Dong 2852dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 2862dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 2872dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 2882dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 2892dec2b5be2056c6d9428897dc672185872d30d17James Dong} 2902dec2b5be2056c6d9428897dc672185872d30d17James Dong 2912dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 29325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 29420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 29520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2962dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 2972dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 2982dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 2992dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 3002dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 3012dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3022dec2b5be2056c6d9428897dc672185872d30d17James Dong 3032dec2b5be2056c6d9428897dc672185872d30d17James Dong // System property can overwrite the file offset bits parameter 3042dec2b5be2056c6d9428897dc672185872d30d17James Dong char value[PROPERTY_VALUE_MAX]; 3052dec2b5be2056c6d9428897dc672185872d30d17James Dong if (property_get("media.stagefright.record-64bits", value, NULL) 3062dec2b5be2056c6d9428897dc672185872d30d17James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 3072dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 3082dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3092dec2b5be2056c6d9428897dc672185872d30d17James Dong 310065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 31193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 312a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 313a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 314a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 31593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 316a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 317a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 318a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 319a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3208f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 3218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 3228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 3238f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 3248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 3258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 3268f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 3277837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 3287837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 3297837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 3307837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 3317837c17063a4c50bc856ba59418516fdab731de7James Dong 33220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 33393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 33493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int32_t fileType; 33593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (param && param->findInt32(kKeyFileType, &fileType) && 33693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong fileType != OUTPUT_FORMAT_MPEG_4) { 33793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 33893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } else { 33993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("isom"); 34093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 34193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 34220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 34320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 34493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 34520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 34620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3477837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 34820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3497837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 3502dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 3512dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 3522dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 3532dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3542dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 3557837c17063a4c50bc856ba59418516fdab731de7James Dong } 3567837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 3577837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 3587837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 3597837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 3607837c17063a4c50bc856ba59418516fdab731de7James Dong 3617837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 3627837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 3637837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 3641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 3651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 3661acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 3671acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 3681acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 3691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 3701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 3711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 3721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 3731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 3741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 3751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 376a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 377a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 37820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 3791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 380a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 38125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 38220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 38320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 38437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 385a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mFile == NULL) { 38637187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 387a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 388a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 38937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 390a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 391a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 39237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 39337187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 39437187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 39537187916a486504acaf83bea30147eb5fbf46ae5James Dong } 396a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 39737187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 398a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 399a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 4001c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 4011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("stopWriterThread"); 4021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 4041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 4051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 4071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 4081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 4091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 4111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 4121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 4131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 41437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() { 41520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 41637187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 41720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 41820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 41937187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 4208f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 42120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 42220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 42337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 42437187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 42537187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 42637187916a486504acaf83bea30147eb5fbf46ae5James Dong } 42720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 4298f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 4308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 43120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 43220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 43320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 4357837c17063a4c50bc856ba59418516fdab731de7James Dong 43637187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 43737187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 43837187916a486504acaf83bea30147eb5fbf46ae5James Dong fflush(mFile); 43937187916a486504acaf83bea30147eb5fbf46ae5James Dong fclose(mFile); 44037187916a486504acaf83bea30147eb5fbf46ae5James Dong mFile = NULL; 44137187916a486504acaf83bea30147eb5fbf46ae5James Dong mStarted = false; 44237187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 44337187916a486504acaf83bea30147eb5fbf46ae5James Dong } 44437187916a486504acaf83bea30147eb5fbf46ae5James Dong 44520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 4461acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 4471acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 4481acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 4491acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 4, mFile); 4501acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 4511acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset + 8, SEEK_SET); 4521acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 4531acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 4541acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 8, mFile); 4551acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 4567837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 45720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 45820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 4597837c17063a4c50bc856ba59418516fdab731de7James Dong const off_t moovOffset = mOffset; 4607837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 4617837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 4627837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4637837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 464c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6; 46520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 46620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 46720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 46820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 46920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 47020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 47120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 4728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong writeInt32(mTimeScale); // mvhd timescale 4731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(duration); 4741acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(0x10000); // rate: 1.0 47520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 47620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 47720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 47820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 47920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); // matrix 48020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 48120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 48220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 48320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); 48420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 48520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 48620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 48720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x40000000); 48820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 48920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 49020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 49120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 49220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 49320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 49420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 49520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 49620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 49720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 49820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 49920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 5001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong (*it)->writeTrackHeader(id, mUse32BitOffset); 50120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 50220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 50320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5047837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 5057837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 5067837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 5077837c17063a4c50bc856ba59418516fdab731de7James Dong 5087837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 5097837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 5107837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 5117837c17063a4c50bc856ba59418516fdab731de7James Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); 5127837c17063a4c50bc856ba59418516fdab731de7James Dong 5137837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 5142dec2b5be2056c6d9428897dc672185872d30d17James Dong fseeko(mFile, mOffset, SEEK_SET); 5157837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 5167837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 5177837c17063a4c50bc856ba59418516fdab731de7James Dong 5187837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 5197837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 5207837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 5217837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 5222dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 5232dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 5247837c17063a4c50bc856ba59418516fdab731de7James Dong } 5257837c17063a4c50bc856ba59418516fdab731de7James Dong 5260c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 52720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5287837c17063a4c50bc856ba59418516fdab731de7James Dong fflush(mFile); 52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fclose(mFile); 53020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mFile = NULL; 531a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 53237187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 53320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 53420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53513aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 53613aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 53713aec890216948b0c364f8f92792129d0335f506James Dong return OK; 53813aec890216948b0c364f8f92792129d0335f506James Dong} 53913aec890216948b0c364f8f92792129d0335f506James Dong 54013aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 54113aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 54213aec890216948b0c364f8f92792129d0335f506James Dong} 54313aec890216948b0c364f8f92792129d0335f506James Dong 54413aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 54513aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 54613aec890216948b0c364f8f92792129d0335f506James Dong} 54720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 54813aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 54920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t old_offset = mOffset; 55020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 55220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1, buffer->range_length(), mFile); 55320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 55520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 55720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 55820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 56003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 56103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 56203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 56303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 56403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 56503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 56603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 56703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 56803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 56903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 57003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 57103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 57203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 57313aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 57430ab66297501757d745b9ae10da61adcd891f497Andreas Huber off_t old_offset = mOffset; 57530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 57630ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 57703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 57803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 57903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t x = length >> 24; 58003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 58103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 16) & 0xff; 58203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 58303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 8) & 0xff; 58403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 58503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = length & 0xff; 58603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 58703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 58830ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(length < 65536); 58930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 59030ab66297501757d745b9ae10da61adcd891f497Andreas Huber uint8_t x = length >> 8; 59130ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 59230ab66297501757d745b9ae10da61adcd891f497Andreas Huber x = length & 0xff; 59330ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 59403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 59530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 59630ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 59730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1, length, mFile); 59830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 59903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 60003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOffset += length + 4; 60103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 60230ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset += length + 2; 60303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 60430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 60530ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 60630ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 60730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 6087837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 6097837c17063a4c50bc856ba59418516fdab731de7James Dong const void *ptr, size_t size, size_t nmemb, FILE *stream) { 6107837c17063a4c50bc856ba59418516fdab731de7James Dong 6117837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 6127837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 6131acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 6141acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 6157837c17063a4c50bc856ba59418516fdab731de7James Dong for (List<off_t>::iterator it = mBoxes.begin(); 6167837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 6177837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 6187837c17063a4c50bc856ba59418516fdab731de7James Dong } 6197837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 6207837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream); 6217837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 6227837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 6237837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 6247837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6257837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6267837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6277837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 6287837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6297837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 6307837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 6317837c17063a4c50bc856ba59418516fdab731de7James Dong } 6327837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6337837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 6347837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 6357837c17063a4c50bc856ba59418516fdab731de7James Dong } 6367837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 6377837c17063a4c50bc856ba59418516fdab731de7James Dong} 6387837c17063a4c50bc856ba59418516fdab731de7James Dong 63920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 6400c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 64120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6427837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 6437837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 64720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 64820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 6500c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 65120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t offset = *--mBoxes.end(); 65320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 65420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6557837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 6567837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 6577837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 6587837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6597837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, offset, SEEK_SET); 6607837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 6617837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 6627837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 6637837c17063a4c50bc856ba59418516fdab731de7James Dong } 66420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 66520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 6677837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 1, mFile); 66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 66920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 67020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 6727837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 2, mFile); 67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 67420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 67520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 67620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 6777837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 4, mFile); 67820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 67920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 68020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 68120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 6827837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 8, mFile); 68320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 68420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 68520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 68620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 6877837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, n + 1, mFile); 68820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 68920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 6910c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 6927837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, 4, mFile); 69320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 69420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 6967837c17063a4c50bc856ba59418516fdab731de7James Dong write(data, 1, size, mFile); 69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 699d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 700d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 701d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 702d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 703d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 704d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 705956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 706d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 707d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 708d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 709d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 710d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes); 711d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 712d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 713d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 714d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 715d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 716d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 717d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 718d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 719d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 720d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 721d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 722d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 723d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 724d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 725d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 726d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 727d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 72825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 72925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 73025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 73125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 73225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 73325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 73425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 73525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 73625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 73725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 73825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 73925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 74025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 741f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 742f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 743f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 7443c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 745065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 746f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 747f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 7483c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 7493c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 7503c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 751f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 7523c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 7533c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 7543c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 7553c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 75658ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 75758ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 75858ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 75958ae9c530247668f8af36e30d228c716c226b3d4James Dong} 76058ae9c530247668f8af36e30d228c716c226b3d4James Dong 76120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 76220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 76320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 76425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber MPEG4Writer *owner, const sp<MediaSource> &source) 76520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 76625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 76720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 76820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 769a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 770a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 771c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 772956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 773be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 77420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 77525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 776548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 77725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS(false) { 77819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 7798f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 7801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 7811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 7821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 7831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 7841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 7851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 7861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 787c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 788c059860c73678a202bfa33062723e8f82fb779d9James Dong} 789c059860c73678a202bfa33062723e8f82fb779d9James Dong 790c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 791c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 792c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 793c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 794c059860c73678a202bfa33062723e8f82fb779d9James Dong 795c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 796c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 797c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 798c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 799c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 800c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 801c059860c73678a202bfa33062723e8f82fb779d9James Dong } 802c059860c73678a202bfa33062723e8f82fb779d9James Dong 803c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 804c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 805c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 806c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 807c059860c73678a202bfa33062723e8f82fb779d9James Dong } 808c059860c73678a202bfa33062723e8f82fb779d9James Dong 8098f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 81019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 81119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 81219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 81319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 81419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 81519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 81619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 81719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 81819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 81919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 82019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 82119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 82219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 82319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 82419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 82519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 82619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 82719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 82819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 82919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 83019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 83119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 83219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 83319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 83419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 83519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 83619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 83719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 83819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 83919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 84019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 84120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 84220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 84420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 84520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 84720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 84820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 84920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 85020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 85393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 85493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 85593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 85693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 85793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 85893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 85993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 86093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 86193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 86293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 86393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 86493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 86593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 86693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 8671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 8681c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 8691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 8701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 8711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 8721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 8731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 8741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8751c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 8761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 8771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 8781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 8791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 8811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 8821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 8841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 8851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 8861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 8871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 8911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 8921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8931c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeFirstChunk(ChunkInfo* info) { 8941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeFirstChunk: %p", info->mTrack); 8951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = info->mChunks.begin(); 8971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 8981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != chunkIt->mSamples.end(); ++it) { 8991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = info->mTrack->isAvc() 9011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ? addLengthPrefixedSample_l(*it) 9021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong : addSample_l(*it); 9031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it == chunkIt->mSamples.begin()) { 9041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mTrack->addChunkOffset(offset); 9051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Done with the current chunk. 9091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Release all the samples in this chunk. 9101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!chunkIt->mSamples.empty()) { 9111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 9121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 9131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 9141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.erase(it); 9151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.clear(); 9171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mChunks.erase(chunkIt); 9181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9201c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeChunks() { 9211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeChunks"); 9221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 9231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mChunkInfos.empty()) { 9241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!it->mChunks.empty()) { 9261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(OK, writeOneChunk()); 9271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ++outstandingChunks; 9281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mTrack = NULL; 9301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.erase(it); 9311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 9331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 9341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9361c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::writeOneChunk() { 9371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeOneChunk"); 9381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Find the smallest timestamp, and write that chunk out 9401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // XXX: What if some track is just too slow? 9411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 9421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 9431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 9451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 9461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 9471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 9481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 9491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 9501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 9551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 9561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 9571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 9601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 9611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 9641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 9651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeFirstChunk(&(*it)); 9661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 9691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9711c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 9721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 9731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 9751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 9761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 9771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 9781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(writeOneChunk(), OK); 9791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 9831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Write ALL samples 9841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 9851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeChunks(); 9861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9891c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 9901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 9911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 9931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 994e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 9951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 9961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 9971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 9981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 9991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 10001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 10031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 10041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 10051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 10061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 10071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 10081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 10091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 101093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1011a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1012a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1013a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1014a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1015a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 101625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 101793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 101819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 101919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 102019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 102119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 1022e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = true; 1023e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1024e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1025e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1026e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1027e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1028e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1029e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 103093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 103193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1032f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1033f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1034f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 103525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 103625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 103725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 103825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 103920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 104120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 104220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 104320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1045c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 104625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1047956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 104820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 105020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 105125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 105225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 105320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 105420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 105537187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1056a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 105737187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1058a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1059a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 106037187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 106120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 106237187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 106320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 106420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 106520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 106620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 106720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 106820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 106920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 107037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = (status_t) dummy; 107137187916a486504acaf83bea30147eb5fbf46ae5James Dong 107237187916a486504acaf83bea30147eb5fbf46ae5James Dong { 107337187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = mSource->stop(); 107437187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { 107537187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 107637187916a486504acaf83bea30147eb5fbf46ae5James Dong } 107737187916a486504acaf83bea30147eb5fbf46ae5James Dong } 107837187916a486504acaf83bea30147eb5fbf46ae5James Dong 107937187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 108020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 108120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 108225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 108325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 108425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 108525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 108620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 108720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 108820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 108920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 109037187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 109137187916a486504acaf83bea30147eb5fbf46ae5James Dong return (void *) err; 109220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 109320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1094548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber#include <ctype.h> 1095548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huberstatic void hexdump(const void *_data, size_t size) { 1096548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber const uint8_t *data = (const uint8_t *)_data; 1097548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t offset = 0; 1098548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber while (offset < size) { 1099548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("0x%04x ", offset); 1100548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1101548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t n = size - offset; 1102548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (n > 16) { 1103548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber n = 16; 1104548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1105548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1106548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < 16; ++i) { 1107548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (i == 8) { 1108548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1109548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1110548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1111548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (offset + i < size) { 1112548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%02x ", data[offset + i]); 1113548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 1114548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1115548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1116548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1117548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1118548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1119548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1120548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < n; ++i) { 1121548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (isprint(data[offset + i])) { 1122548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%c", data[offset + i]); 1123548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 1124548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("."); 1125548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1126548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1127548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1128548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("\n"); 1129548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1130548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber offset += 16; 1131548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1132548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber} 1133548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 11343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 11353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 11363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 11383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 11393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 11423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 11433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 11453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 11473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 11483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 11493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 11503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 11523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 11533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 11553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 11583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 11593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 11613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 11623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 11633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 11653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 11663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 11673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 11683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 11693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 11723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 11733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 11743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 11753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 11763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 11783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 11793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 11803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 11813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 11823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 11833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 11843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 11853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 11863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 11873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 11903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 11913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 11923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 11943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 11973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 11983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 11993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 12013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 12023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 12033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 12043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 12083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 12093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 12103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 12113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 12123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 12143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 12153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 12173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 12183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 12193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 12203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 12213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 12223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 12233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 12243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 12253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 12263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 12273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 12283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 12293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 12303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 12313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 12323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 12333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 12363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 12373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 12393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 12403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 12413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 12423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 12453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 12463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 12483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 12493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 12503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 12543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 12583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 12593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 12603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 12613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 12643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 12653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 12663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 12673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 12683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 12723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 12733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 12783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 12793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 12803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 12813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 12823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 12853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 12863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 12913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 12923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 12933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 12943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 12953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 12963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 12973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 13013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1302548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 130303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 130403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1305548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber // hexdump(data, size); 1306548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 130703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1308548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 130903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 131003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 131103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 13133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 131403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 131503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 131603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 13183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 13193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 132003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 132103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 132303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 132403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 132503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 13273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 132803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 132903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 13303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 13313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 13323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 13333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 133403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 133603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 133703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 3; // length size == 4 bytes 133803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 133903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 1; // length size == 2 bytes 134003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 134103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 13433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 13443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 13453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 13463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 13473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 13483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 13493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 13503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 13513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 13523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 13543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 13553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 13563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 13593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 13603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 13613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 13623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 13633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 13643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 13653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 13663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 13673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 13683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 13703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 13713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 13723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 137303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 137403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 137503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 137603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13778644c14618d30d9e57a69df40ed939986ebf02c4James Dongstatic bool collectStatisticalData() { 13788644c14618d30d9e57a69df40ed939986ebf02c4James Dong char value[PROPERTY_VALUE_MAX]; 13798644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (property_get("media.stagefright.record-stats", value, NULL) 13808644c14618d30d9e57a69df40ed939986ebf02c4James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 13818644c14618d30d9e57a69df40ed939986ebf02c4James Dong return true; 13828644c14618d30d9e57a69df40ed939986ebf02c4James Dong } 13838644c14618d30d9e57a69df40ed939986ebf02c4James Dong return false; 13848644c14618d30d9e57a69df40ed939986ebf02c4James Dong} 13858644c14618d30d9e57a69df40ed939986ebf02c4James Dong 138637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 138730ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 138813aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 138913aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 139013aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 139113aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 13928f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 13938f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1394c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1395c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 13968f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1397be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1398a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 13991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1400e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1401e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t wallClockTimeUs = 0; 1402e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t lastWallClockTimeUs = 0; 1403e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1404d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 14058644c14618d30d9e57a69df40ed939986ebf02c4James Dong bool collectStats = collectStatisticalData(); 140620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1407ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 14081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMaxWriteTimeUs = 0; 140993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 141020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 141193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 141220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 141320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 141420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 141513aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 141620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 141720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 141820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1419a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1420a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1421a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1422a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1423a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1424a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1425a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1426a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1427a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 142830ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 142930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 143003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 143103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 143203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1433548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1434548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 14351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 143603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 143703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 143803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 143903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1440be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 14411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 144203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 144303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 144403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 144503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 144603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 144703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 144830ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 144930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 145030ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 145130ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 145230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1453548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 145430ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 1455a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1456a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1457d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 1458d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 1459d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1460d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1461d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 1462d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 1463d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 1464d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 1465d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 1466d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 14671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 1468e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 14698644c14618d30d9e57a69df40ed939986ebf02c4James Dong size_t sampleSize; 14701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong sampleSize = mIsAvc 147103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 1472d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 4 147303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 1474d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 2 147503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 1476d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong : copy->range_length(); 1477050b28a593350047845a45a14cc5026221ac1620James Dong 1478d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 14798644c14618d30d9e57a69df40ed939986ebf02c4James Dong mEstimatedTrackSizeBytes += sampleSize; 1480d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 1481d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1482d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1483d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1484d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 1485d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1486d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1487d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1488d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1489050b28a593350047845a45a14cc5026221ac1620James Dong 1490d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 1491d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1492d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1493d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 1494d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1495d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 14968644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 1497f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 1498f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 14993c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 150048c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 1501a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 1502c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong previousPausedDurationUs += (timestampUs - mTrackDurationUs - lastDurationUs); 1503a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 1504a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1505a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1506a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 1507e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mIsRealTimeRecording && !mIsAudio) { 1508e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // The minor adjustment on the timestamp is heuristic/experimental 1509e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // We are adjusting the timestamp to reduce the fluctuation of the duration 1510e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // of neighboring samples. This in turn helps reduce the track header size, 1511e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // especially, the number of entries in the "stts" box. 1512e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1513e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t durationUs = timestampUs + mOwner->getDriftTimeUs() - lastTimestampUs; 1514e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t diffUs = (durationUs > lastDurationUs) 1515e259531ce59ab1f31de5a23124b22536f6a5a767James Dong ? durationUs - lastDurationUs 1516e259531ce59ab1f31de5a23124b22536f6a5a767James Dong : lastDurationUs - durationUs; 1517e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (diffUs <= 5000) { // XXX: Magic number 5ms 1518e259531ce59ab1f31de5a23124b22536f6a5a767James Dong timestampUs = lastTimestampUs + lastDurationUs; 1519e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } else { 1520e259531ce59ab1f31de5a23124b22536f6a5a767James Dong timestampUs += mOwner->getDriftTimeUs(); 1521e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1522e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1523e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1524e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 1525e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1526e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 1527e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGW("Drop a frame, since it arrives too late!"); 1528e259531ce59ab1f31de5a23124b22536f6a5a767James Dong copy->release(); 1529e259531ce59ab1f31de5a23124b22536f6a5a767James Dong copy = NULL; 1530e259531ce59ab1f31de5a23124b22536f6a5a767James Dong continue; 1531e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1532e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1533e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1534a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong LOGV("time stamp: %lld and previous paused duration %lld", 1535a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs, previousPausedDurationUs); 1536c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 1537c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 15383b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 15393b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 15408644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 1541ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 1542ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 1543c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 1544c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 1545c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 1546c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 1547c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 1548c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 1549c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 1550c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 1551c059860c73678a202bfa33062723e8f82fb779d9James Dong 1552c059860c73678a202bfa33062723e8f82fb779d9James Dong if (currDurationTicks != lastDurationTicks) { 15538f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1554be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 1555be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 1556be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1557be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 1558be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1559be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1560be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1561ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 1562be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 1563be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 15648644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 1565be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 15668644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 1567c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 15688644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 1569e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mIsRealTimeRecording && mIsAudio) { 1570e259531ce59ab1f31de5a23124b22536f6a5a767James Dong wallClockTimeUs = systemTime() / 1000; 1571e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t wallClockDurationUs = wallClockTimeUs - lastWallClockTimeUs; 1572e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 2) { 1573e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mOwner->addDriftTimeUs(lastDurationUs - wallClockDurationUs); 1574e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1575e259531ce59ab1f31de5a23124b22536f6a5a767James Dong lastWallClockTimeUs = wallClockTimeUs; 1576e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 157720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1578d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 1579ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mStssTableEntries.push_back(mNumSamples); 1580d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 1581d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 158293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 158393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 158493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 158593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 1586faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 158793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 158858ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 15891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 159058ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 159158ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 159258ae9c530247668f8af36e30d228c716c226b3d4James Dong mChunkOffsets.push_back(offset); 159358ae9c530247668f8af36e30d228c716c226b3d4James Dong } 159458ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 159558ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 159658ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 159758ae9c530247668f8af36e30d228c716c226b3d4James Dong } 159813aec890216948b0c364f8f92792129d0335f506James Dong 159913aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 160013aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 160113aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(++nChunks, 1, 1); 160213aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 16031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 160413aec890216948b0c364f8f92792129d0335f506James Dong } else { 160513aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 160613aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 160713aec890216948b0c364f8f92792129d0335f506James Dong } else { 160813aec890216948b0c364f8f92792129d0335f506James Dong if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 160913aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 16108644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (collectStats) { 16118644c14618d30d9e57a69df40ed939986ebf02c4James Dong mChunkDurations.push_back(timestampUs - chunkTimestampUs); 16128644c14618d30d9e57a69df40ed939986ebf02c4James Dong } 161313aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 161413aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 161513aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 161613aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, 161713aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size(), 1); 161813aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 161913aec890216948b0c364f8f92792129d0335f506James Dong } 16201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 162113aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 162213aec890216948b0c364f8f92792129d0335f506James Dong } 162313aec890216948b0c364f8f92792129d0335f506James Dong } 162413aec890216948b0c364f8f92792129d0335f506James Dong } 162513aec890216948b0c364f8f92792129d0335f506James Dong 162620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 162725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 16288644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 162937187916a486504acaf83bea30147eb5fbf46ae5James Dong err = ERROR_MALFORMED; 1630690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else if (OK != checkCodecSpecificData()) { 1631690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 1632f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 1633faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, -1, err); 1634be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 163513aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 163658ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 1637ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong StscTableEntry stscEntry(1, mNumSamples, 1); 163858ae9c530247668f8af36e30d228c716c226b3d4James Dong mStscTableEntries.push_back(stscEntry); 163958ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 164013aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 164113aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1); 164213aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 16431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 164413aec890216948b0c364f8f92792129d0335f506James Dong } 164513aec890216948b0c364f8f92792129d0335f506James Dong 1646be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 1647be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 1648be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 1649ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 16508f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 1651be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1652be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 1653be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 16548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1655be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 1656c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 165725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 16581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. Max write time: %lld us - %s", 16591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong count, nZeroLengthFrames, mNumSamples, mMaxWriteTimeUs, mIsAudio? "audio": "video"); 1660365a963142093a1cd8efdcea76b5f65096a5b115James Dong 16611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong logStatisticalData(mIsAudio); 166237187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 166337187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 166437187916a486504acaf83bea30147eb5fbf46ae5James Dong } 166537187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 1666365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1667365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1668faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 1669faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 1670215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 1671215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 167293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 1673faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err); 167493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 167593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 167693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 167793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1678faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 1679faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong const MPEG4Writer::Track* track, int64_t timeUs, status_t err) { 1680faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 1681faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t nTracks = mTracks.size(); 1682faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks >= 1); 1683faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks < 64); // Arbitrary number 1684faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1685faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t trackNum = 0; 1686faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#if 0 1687faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // In the worst case, we can put the trackNum 1688faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // along with MEDIA_RECORDER_INFO_COMPLETION_STATUS 1689faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // to report the progress. 1690faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong for (List<Track *>::iterator it = mTracks.begin(); 1691faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong it != mTracks.end(); ++it, ++trackNum) { 1692faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (track == (*it)) { 1693faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong break; 1694faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1695faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1696faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#endif 1697faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(trackNum < nTracks); 1698faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum <<= 16; 1699faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1700faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 1701faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 1702faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 1703faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_ERROR, 1704faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_ERROR_UNKNOWN, 1705faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 1706faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 1707faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1708faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1709faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 1710faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 1711faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 1712faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS, 1713faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 1714faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 1715faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 1716faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 1717faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 1718faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, 1719faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 1720faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1721faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 1722faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1723215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dongvoid MPEG4Writer::Track::findMinAvgMaxSampleDurationMs( 1724215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t *min, int32_t *avg, int32_t *max) { 17258644c14618d30d9e57a69df40ed939986ebf02c4James Dong CHECK(!mSampleSizes.empty()); 1726c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int32_t avgSampleDurationMs = mTrackDurationUs / 1000 / mNumSamples; 1727215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t minSampleDurationMs = 0x7FFFFFFF; 1728215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t maxSampleDurationMs = 0; 1729365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1730365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != mSttsTableEntries.end(); ++it) { 17318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleDurationMs = 17328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000; 1733215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (sampleDurationMs > maxSampleDurationMs) { 1734215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong maxSampleDurationMs = sampleDurationMs; 1735215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong } else if (sampleDurationMs < minSampleDurationMs) { 1736215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong minSampleDurationMs = sampleDurationMs; 1737365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1738215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("sample duration: %d ms", sampleDurationMs); 1739365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1740215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(minSampleDurationMs != 0); 1741215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(avgSampleDurationMs != 0); 1742215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(maxSampleDurationMs != 0); 1743215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *min = minSampleDurationMs; 1744215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *avg = avgSampleDurationMs; 1745215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *max = maxSampleDurationMs; 1746365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1747365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1748365a963142093a1cd8efdcea76b5f65096a5b115James Dong// Don't count the last duration 1749365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) { 1750365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1751365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunkDuration = duration; 1752365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t maxChunkDuration = duration; 1753365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (mChunkDurations.size() > 1) { 1754365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<int64_t>::iterator it = mChunkDurations.begin(); 1755365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != --mChunkDurations.end(); ++it) { 1756365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (minChunkDuration > (*it)) { 1757365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunkDuration = (*it); 1758365a963142093a1cd8efdcea76b5f65096a5b115James Dong } else if (maxChunkDuration < (*it)) { 1759365a963142093a1cd8efdcea76b5f65096a5b115James Dong maxChunkDuration = (*it); 1760365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1761365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1762365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1763365a963142093a1cd8efdcea76b5f65096a5b115James Dong *min = minChunkDuration; 1764365a963142093a1cd8efdcea76b5f65096a5b115James Dong *max = maxChunkDuration; 1765365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1766365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1767365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::logStatisticalData(bool isAudio) { 1768c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (mTrackDurationUs <= 0 || mSampleSizes.empty()) { 1769365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("nothing is recorded"); 1770365a963142093a1cd8efdcea76b5f65096a5b115James Dong return; 1771365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1772365a963142093a1cd8efdcea76b5f65096a5b115James Dong 17738644c14618d30d9e57a69df40ed939986ebf02c4James Dong bool collectStats = collectStatisticalData(); 1774365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1775365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (collectStats) { 1776215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("%s track - duration %lld us, total %d frames", 1777c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong isAudio? "audio": "video", mTrackDurationUs, 1778ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples); 1779215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t min, avg, max; 1780215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong findMinAvgMaxSampleDurationMs(&min, &avg, &max); 1781215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max); 1782215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (!isAudio) { 1783215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float avgFps = 1000.0 / avg; 1784215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float minFps = 1000.0 / max; 1785215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float maxFps = 1000.0 / min; 1786365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f", 1787215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong minFps, avgFps, maxFps); 1788365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1789365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1790365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t totalBytes = 0; 17918644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 17928644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 17938644c14618d30d9e57a69df40ed939986ebf02c4James Dong totalBytes += (*it); 1794365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1795c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong float bitRate = (totalBytes * 8000000.0) / mTrackDurationUs; 1796365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("avg bit rate (bps): %.2f", bitRate); 1797365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1798365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1799365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (duration != 0) { // If interleaving is enabled 1800365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunk, maxChunk; 1801365a963142093a1cd8efdcea76b5f65096a5b115James Dong findMinMaxChunkDurations(&minChunk, &maxChunk); 1802365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld", 1803365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunk, duration, maxChunk); 1804365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1805365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 180613aec890216948b0c364f8f92792129d0335f506James Dong} 180713aec890216948b0c364f8f92792129d0335f506James Dong 1808e259531ce59ab1f31de5a23124b22536f6a5a767James Dongvoid MPEG4Writer::addDriftTimeUs(int64_t driftTimeUs) { 1809e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("addDriftTimeUs: %lld us", driftTimeUs); 1810e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 1811e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs += driftTimeUs; 1812e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 1813e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1814e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 1815e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 1816e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 1817e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 1818e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 1819e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 18201c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 18211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 18221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 18231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t startTimeUs = systemTime() / 1000; 18241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 18251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 182613aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 18271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t endTimeUs = systemTime() / 1000; 18281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mMaxWriteTimeUs < endTimeUs - startTimeUs) { 18291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMaxWriteTimeUs = endTimeUs - startTimeUs; 18301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 183120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 183220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18333b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 1834c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 183520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 183620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1837d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 1838d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 1839d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1840d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1841690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 1842690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 1843690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 1844690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 1845690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 1846690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1847690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 1848690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 1849690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Missing codec specific data 1850690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 1851690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 1852690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 1853690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 1854690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 1855690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Unexepected codec specific data found 1856690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 1857690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 1858690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 1859690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 1860690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 1861690f546b0ee548dbfe997df36418e5302ec2d786James Dong 18621acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader( 18631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t trackID, bool use32BitOffset) { 186420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 186520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 18660c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 186720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 18691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 18708f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 187120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 18728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 18738f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 187420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 187520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 187620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 187720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 18781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Flags = 7 to indicate that the track is enabled, and 18791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // part of the presentation 18801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x07); // version=0, flags=7 188120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 188220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 188320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 188420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 18858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t tkhdDuration = 18868f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 18878f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 188820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 188920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 189020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 189120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 18921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 189320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 189420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 189520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); // matrix 189620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 189720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 189820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 189920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); 190020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 190120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 190220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 190320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x40000000); 190420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 190620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 190720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 190820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 190920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 191020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 191120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 19120c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 191320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1914050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 1915050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 191620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 191720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 191820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1919f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 1920f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong if (mStartTimestampUs != moovStartTimeUs) { 19213c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("edts"); 19223c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("elst"); 19231acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 19241acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(2); // never ends with an empty list 19258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 19268f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // First elst entry: specify the starting time offset 19278f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; 19288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; 19298f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timecale 19308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(-1); // starting time offset 19318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(1 << 16); // rate = 1.0 19328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 19338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // Second elst entry: specify the track duration 19348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 19358f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timescale 19361acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); 19371acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); 19383c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 19393c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 19403c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 19413c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 194220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 194320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 194420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 194520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 194620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 194720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 19488f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mTimeScale); // media timescale 19498f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 19508f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mdhdDuration); // use media timescale 19511acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Language follows the three letter standard ISO-639-2/T 19521acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // 'e', 'n', 'g' for "English", for instance. 19531acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Each character is packed as the difference between its ASCII value and 0x60. 19541acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // For "English", these are 00101, 01110, 00111. 19551acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // XXX: Where is the padding bit located: 0x15C7? 19561acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(0); // language code 195720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 195820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 195920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 196020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 196120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 1962050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // component type: should be mhlr 19631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 196420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 196520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 196620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 19671acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Removing "r" for the name string just makes the string 4 byte aligned 19681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 196920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 197020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 197120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 19721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 197320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 197420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 197520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 197620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 197720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 197820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 197920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 19801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x01); // version=0, flags=1 198120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 198220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 198320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 198420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 198520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 198620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 1987050b28a593350047845a45a14cc5026221ac1620James Dong 1988050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dinf"); 1989050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dref"); 1990050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 19911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // entry count (either url or urn) 19921acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // The table index here refers to the sample description index 19931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // in the sample table entries. 1994050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("url "); 19951acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 1996050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // url 1997050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dref 1998050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dinf 1999050b28a593350047845a45a14cc5026221ac1620James Dong 200020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 200120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 200220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 200320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 200420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 20051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 200625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 200718291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 200825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 200918291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 201025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 2011050b28a593350047845a45a14cc5026221ac1620James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2012050b28a593350047845a45a14cc5026221ac1620James Dong fourcc = "mp4a"; 201325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 201425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 201525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 201625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 201725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 201825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 201920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 202020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 2021050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x1); // data ref index 202220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 202320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 2024050b28a593350047845a45a14cc5026221ac1620James Dong int32_t nChannels; 2025050b28a593350047845a45a14cc5026221ac1620James Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2026050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(nChannels); // channel count 202720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 202820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 202920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 203020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 203120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 203220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 20330c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 203420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 2035050b28a593350047845a45a14cc5026221ac1620James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2036050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("esds"); 203751dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 203851dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 2039050b28a593350047845a45a14cc5026221ac1620James Dong 2040050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2041050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x03); // ES_DescrTag 2042050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2043050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x0000);// ES_ID 2044050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); 2045050b28a593350047845a45a14cc5026221ac1620James Dong 2046050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2047050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2048050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2049050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x15); // streamType AudioStream 2050050b28a593350047845a45a14cc5026221ac1620James Dong 2051050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x03); // XXX 2052050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2053050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // max bit rate 2054050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // avg bit rate 2055050b28a593350047845a45a14cc5026221ac1620James Dong 2056050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2057050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(mCodecSpecificDataSize); 2058050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2059050b28a593350047845a45a14cc5026221ac1620James Dong 2060050b28a593350047845a45a14cc5026221ac1620James Dong static const uint8_t kData2[] = { 2061050b28a593350047845a45a14cc5026221ac1620James Dong 0x06, // SLConfigDescriptorTag 2062050b28a593350047845a45a14cc5026221ac1620James Dong 0x01, 2063050b28a593350047845a45a14cc5026221ac1620James Dong 0x02 2064050b28a593350047845a45a14cc5026221ac1620James Dong }; 2065050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(kData2, sizeof(kData2)); 2066050b28a593350047845a45a14cc5026221ac1620James Dong 2067050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // esds 20685aff464f67322cd13dc8ed165806971cfff2e4d5James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 20695aff464f67322cd13dc8ed165806971cfff2e4d5James Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 20705aff464f67322cd13dc8ed165806971cfff2e4d5James Dong // 3gpp2 Spec AMRSampleEntry fields 20715aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->beginBox("damr"); 20725aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeCString(" "); // vendor: 4 bytes 20735aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // decoder version 20745aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 20755aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // mode change period 20765aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(1); // frames per sample 20775aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->endBox(); 2078050b28a593350047845a45a14cc5026221ac1620James Dong } 207920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 208020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 208118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 208220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 208318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 208420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 208530ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 208630ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 208720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 208825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 20890c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 209020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 209120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 209220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 209320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 20941acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(1); // data ref index 209520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 209620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 209720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 209820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 209920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 210020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 210120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 210220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 210320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 21040c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 210520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 210620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 210720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 210820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 210920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 211020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 211120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 211220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 211320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 211420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 211520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21160c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 211720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 211818291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2119a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificData); 2120a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificDataSize > 0); 212120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 212220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 212320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 212420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 212520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 212620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 212720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 212820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 212920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 213020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 213120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 213220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 213320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 213420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 213520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 213620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 213720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 213820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 213920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 214020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 2141050b28a593350047845a45a14cc5026221ac1620James Dong 214220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 214320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 214420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 214520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 214620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 214720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 214820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 214920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 215020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 215120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 215220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 215320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 215420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 215518291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 215620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 215720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 215820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 215920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 216020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 216120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 216220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 216320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 216430ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 216551dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 216651dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 216730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 216830ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 216930ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 217020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 217130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 21721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox("pasp"); 21731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // This is useful if the pixel is not square 21741acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // hspacing 21751acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // vspacing 21761acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // pasp 217730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 217820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 217920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 218020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 218120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 218220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2183be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(mSttsTableEntries.size()); 2184c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t prevTimestampUs = 0; 2185be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 2186be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSttsTableEntries.end(); ++it) { 2187be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleCount); 2188c059860c73678a202bfa33062723e8f82fb779d9James Dong 2189c059860c73678a202bfa33062723e8f82fb779d9James Dong // Make sure that we are calculating the sample duration the exactly 2190c059860c73678a202bfa33062723e8f82fb779d9James Dong // same way as we made decision on how to create stts entries. 2191c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; 2192c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - 2193c059860c73678a202bfa33062723e8f82fb779d9James Dong (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2194c059860c73678a202bfa33062723e8f82fb779d9James Dong prevTimestampUs += (it->sampleCount * it->sampleDurationUs); 2195c059860c73678a202bfa33062723e8f82fb779d9James Dong 21968f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(dur); 219720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 219820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 219920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!mIsAudio) { 2201050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("stss"); 2202050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2203050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames 2204050b28a593350047845a45a14cc5026221ac1620James Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2205050b28a593350047845a45a14cc5026221ac1620James Dong it != mStssTableEntries.end(); ++it) { 2206050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(*it); 2207050b28a593350047845a45a14cc5026221ac1620James Dong } 2208050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // stss 2209050b28a593350047845a45a14cc5026221ac1620James Dong } 2210050b28a593350047845a45a14cc5026221ac1620James Dong 221120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 221220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2213be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 22148644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t>::iterator it = mSampleSizes.begin(); 22158644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); // default sample size 2216be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2217be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(0); 2218be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2219ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mOwner->writeInt32(mNumSamples); 2220be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (!mSamplesHaveSameSize) { 22218644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 22228644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 22238644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); 2224be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 222520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 222620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 222720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 222820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 222920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 223013aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mStscTableEntries.size()); 223113aec890216948b0c364f8f92792129d0335f506James Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 223213aec890216948b0c364f8f92792129d0335f506James Dong it != mStscTableEntries.end(); ++it) { 223313aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->firstChunk); 223413aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->samplesPerChunk); 223513aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->sampleDescriptionId); 223620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 223720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 22381acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 223920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 224013aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mChunkOffsets.size()); 224113aec890216948b0c364f8f92792129d0335f506James Dong for (List<off_t>::iterator it = mChunkOffsets.begin(); 224213aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkOffsets.end(); ++it) { 22431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (use32BitOffset) { 22441acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 22451acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 22461acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt64((*it)); 22471acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 224820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 22498f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->endBox(); // stco or co64 225020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 225120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 22521acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // minf 225320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 225420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 225520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 225620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 225720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2258