MPEG4Writer.cpp revision c059860c73678a202bfa33062723e8f82fb779d9
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); 5120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void stop(); 52a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong void 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); 14720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void 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 17720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 17820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 17920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 18020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#define USE_NALLEN_FOUR 1 18203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 18320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mFile(fopen(filename, "wb")), 1851acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 186a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 187a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 18820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 18913aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 1907837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 191f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 1920c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mFile != NULL); 19320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 19420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19530ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 19630ab66297501757d745b9ae10da61adcd891f497Andreas Huber : mFile(fdopen(fd, "wb")), 1971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 198a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 199a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 20030ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 20113aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2027837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 203f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 20430ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(mFile != NULL); 20530ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 20630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 20720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 20820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 20920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 21120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 21220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 21420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 21520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 21620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2172dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 21825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track *track = new Track(this, source); 21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 2202dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 2212dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 22220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 22320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 225a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 226a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 22793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 228a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 229a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 230a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 231a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 232a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 233a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 234a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 235a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 236a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 237a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 238a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 239a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 240a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2412dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 2422dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 2432dec2b5be2056c6d9428897dc672185872d30d17James Dong // 2442dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 2452dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 2462dec2b5be2056c6d9428897dc672185872d30d17James Dong // Currently, lets set to 0.4% for now. 2472dec2b5be2056c6d9428897dc672185872d30d17James Dong 2482dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB, 2492dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 2502dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 4 2512dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 2522dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 2532dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 2542dec2b5be2056c6d9428897dc672185872d30d17James Dong 2552dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 2562dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 2572dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 2582dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024; // 4 KB 2592dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 2602dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 2612dec2b5be2056c6d9428897dc672185872d30d17James Dong 2622dec2b5be2056c6d9428897dc672185872d30d17James Dong if (mMaxFileSizeLimitBytes != 0) { 2632dec2b5be2056c6d9428897dc672185872d30d17James Dong size = mMaxFileSizeLimitBytes * 4 / 1000; 2642dec2b5be2056c6d9428897dc672185872d30d17James Dong } else if (mMaxFileDurationLimitUs != 0) { 2652dec2b5be2056c6d9428897dc672185872d30d17James Dong if (bitRate <= 0) { 2662dec2b5be2056c6d9428897dc672185872d30d17James Dong // We could not estimate the file size since bitRate is not set. 2672dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 2682dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 2692dec2b5be2056c6d9428897dc672185872d30d17James Dong size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000); 2702dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2712dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2722dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 2732dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 2742dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2752dec2b5be2056c6d9428897dc672185872d30d17James Dong 2762dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 2772dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 2782dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 2792dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 2802dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2812dec2b5be2056c6d9428897dc672185872d30d17James Dong 2822dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 2832dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 2842dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 2852dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 2862dec2b5be2056c6d9428897dc672185872d30d17James Dong} 2872dec2b5be2056c6d9428897dc672185872d30d17James Dong 2882dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 28920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 29025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 29120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2932dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 2942dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 2952dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 2962dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 2972dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 2982dec2b5be2056c6d9428897dc672185872d30d17James Dong } 2992dec2b5be2056c6d9428897dc672185872d30d17James Dong 3002dec2b5be2056c6d9428897dc672185872d30d17James Dong // System property can overwrite the file offset bits parameter 3012dec2b5be2056c6d9428897dc672185872d30d17James Dong char value[PROPERTY_VALUE_MAX]; 3022dec2b5be2056c6d9428897dc672185872d30d17James Dong if (property_get("media.stagefright.record-64bits", value, NULL) 3032dec2b5be2056c6d9428897dc672185872d30d17James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 3042dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 3052dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3062dec2b5be2056c6d9428897dc672185872d30d17James Dong 307065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 30893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 309a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 310a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 311a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 31293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 313a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 314a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 315a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 316a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 3188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 3198f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 3208f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 3218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 3228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 3238f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 3247837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 3257837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 3267837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 3277837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 3287837c17063a4c50bc856ba59418516fdab731de7James Dong 32920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 33093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 33193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int32_t fileType; 33293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (param && param->findInt32(kKeyFileType, &fileType) && 33393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong fileType != OUTPUT_FORMAT_MPEG_4) { 33493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 33593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } else { 33693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("isom"); 33793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 33893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 33920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 34020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 34193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 34220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 34320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3447837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 34520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3467837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 3472dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 3482dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 3492dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 3502dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3512dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 3527837c17063a4c50bc856ba59418516fdab731de7James Dong } 3537837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 3547837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 3557837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 3567837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 3577837c17063a4c50bc856ba59418516fdab731de7James Dong 3587837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 3597837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 3607837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 3611acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 3621acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 3631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 3641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 3651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 3661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 3671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 3681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 3691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 3701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 3711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 3721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 373a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 374a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 37520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 3761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 377a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 37825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 37920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 38020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 381a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dongvoid MPEG4Writer::pause() { 382a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mFile == NULL) { 383a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return; 384a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 385a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 386a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 387a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 388a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it)->pause(); 389a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 390a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 391a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3921c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 3931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("stopWriterThread"); 3941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 3951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 3961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 3971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 3981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 3991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 4001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 4011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 4031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 4041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 4051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 40620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::stop() { 40720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 40820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return; 40920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 41020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4118f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 41220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 41320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 41420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber (*it)->stop(); 41520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4168f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 4178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 4188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 41920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 42020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 42120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 4237837c17063a4c50bc856ba59418516fdab731de7James Dong 42420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 4251acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 4261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 4271acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 4281acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 4, mFile); 4291acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 4301acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset + 8, SEEK_SET); 4311acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 4321acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 4331acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 8, mFile); 4341acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 4357837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 43620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 43720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 4387837c17063a4c50bc856ba59418516fdab731de7James Dong const off_t moovOffset = mOffset; 4397837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 4407837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 4417837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4427837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 443c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6; 44420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 44520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 44620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 44720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 44820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 44920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 45020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 4518f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong writeInt32(mTimeScale); // mvhd timescale 4521acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(duration); 4531acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(0x10000); // rate: 1.0 45420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 45520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 45620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 45720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 45820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); // matrix 45920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 46020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 46120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 46220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); 46320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 46420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 46520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 46620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x40000000); 46720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 46820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 46920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 47020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 47120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 47220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 47320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 47420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 47520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 47620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 47720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 47820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 4791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong (*it)->writeTrackHeader(id, mUse32BitOffset); 48020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 48120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 48220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4837837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 4847837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 4857837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 4867837c17063a4c50bc856ba59418516fdab731de7James Dong 4877837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 4887837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 4897837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 4907837c17063a4c50bc856ba59418516fdab731de7James Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); 4917837c17063a4c50bc856ba59418516fdab731de7James Dong 4927837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 4932dec2b5be2056c6d9428897dc672185872d30d17James Dong fseeko(mFile, mOffset, SEEK_SET); 4947837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 4957837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 4967837c17063a4c50bc856ba59418516fdab731de7James Dong 4977837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 4987837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 4997837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 5007837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 5012dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 5022dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 5037837c17063a4c50bc856ba59418516fdab731de7James Dong } 5047837c17063a4c50bc856ba59418516fdab731de7James Dong 5050c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 50620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5077837c17063a4c50bc856ba59418516fdab731de7James Dong fflush(mFile); 50820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fclose(mFile); 50920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mFile = NULL; 510a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 51120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 51220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 51313aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 51413aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 51513aec890216948b0c364f8f92792129d0335f506James Dong return OK; 51613aec890216948b0c364f8f92792129d0335f506James Dong} 51713aec890216948b0c364f8f92792129d0335f506James Dong 51813aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 51913aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 52013aec890216948b0c364f8f92792129d0335f506James Dong} 52113aec890216948b0c364f8f92792129d0335f506James Dong 52213aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 52313aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 52413aec890216948b0c364f8f92792129d0335f506James Dong} 52520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 52613aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 52720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t old_offset = mOffset; 52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 53020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1, buffer->range_length(), mFile); 53120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 53320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 53520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 53620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 53803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 53903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 54003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 54103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 54203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 54303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 54403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 54503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 54603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 54703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 54803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 54903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 55003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 55113aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 55230ab66297501757d745b9ae10da61adcd891f497Andreas Huber off_t old_offset = mOffset; 55330ab66297501757d745b9ae10da61adcd891f497Andreas Huber 55430ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 55503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 55603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 55703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t x = length >> 24; 55803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 55903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 16) & 0xff; 56003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 56103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 8) & 0xff; 56203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 56303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = length & 0xff; 56403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 56503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 56630ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(length < 65536); 56730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 56830ab66297501757d745b9ae10da61adcd891f497Andreas Huber uint8_t x = length >> 8; 56930ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 57030ab66297501757d745b9ae10da61adcd891f497Andreas Huber x = length & 0xff; 57130ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 57203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 57330ab66297501757d745b9ae10da61adcd891f497Andreas Huber 57430ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 57530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1, length, mFile); 57630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 57703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 57803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOffset += length + 4; 57903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 58030ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset += length + 2; 58103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 58230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 58330ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 58430ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 58530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 5867837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 5877837c17063a4c50bc856ba59418516fdab731de7James Dong const void *ptr, size_t size, size_t nmemb, FILE *stream) { 5887837c17063a4c50bc856ba59418516fdab731de7James Dong 5897837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 5907837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 5911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 5921acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 5937837c17063a4c50bc856ba59418516fdab731de7James Dong for (List<off_t>::iterator it = mBoxes.begin(); 5947837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 5957837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 5967837c17063a4c50bc856ba59418516fdab731de7James Dong } 5977837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 5987837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream); 5997837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 6007837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 6017837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 6027837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6037837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6047837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6057837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 6067837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6077837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 6087837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 6097837c17063a4c50bc856ba59418516fdab731de7James Dong } 6107837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6117837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 6127837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 6137837c17063a4c50bc856ba59418516fdab731de7James Dong } 6147837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 6157837c17063a4c50bc856ba59418516fdab731de7James Dong} 6167837c17063a4c50bc856ba59418516fdab731de7James Dong 61720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 6180c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 61920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6207837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 6217837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 62220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 62320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 62420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 62520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 62620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 62720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 6280c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 62920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 63020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t offset = *--mBoxes.end(); 63120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 63220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6337837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 6347837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 6357837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 6367837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6377837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, offset, SEEK_SET); 6387837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 6397837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 6407837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 6417837c17063a4c50bc856ba59418516fdab731de7James Dong } 64220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 6457837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 1, mFile); 64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 64720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 6507837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 2, mFile); 65120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 65220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 65420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 6557837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 4, mFile); 65620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 65720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 6607837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 8, mFile); 66120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 66220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 66320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 66420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 6657837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, n + 1, mFile); 66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 66720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 6690c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 6707837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, 4, mFile); 67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 67220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 6747837c17063a4c50bc856ba59418516fdab731de7James Dong write(data, 1, size, mFile); 67520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 67620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 677d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 678d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 679d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 680d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 681d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 682d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 683956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 684d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 685d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 686d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 687d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 688d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes); 689d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 690d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 691d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 692d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 693d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 694d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 695d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 696d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 697d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 698d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 699d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 700d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 701d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 702d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 703d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 704d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 705d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 70625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 70725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 70825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 70925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 71025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 71125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 71225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 71325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 71425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 71525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 71625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 71725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 71825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 719f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 720f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 721f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 7223c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 723065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 724f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 725f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 7263c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 7273c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 7283c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 729f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 7303c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 7313c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 7323c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 7333c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 73458ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 73558ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 73658ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 73758ae9c530247668f8af36e30d228c716c226b3d4James Dong} 73858ae9c530247668f8af36e30d228c716c226b3d4James Dong 73920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 74020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 74120111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 74225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber MPEG4Writer *owner, const sp<MediaSource> &source) 74320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 74425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 74520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 74620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 747a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 748a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 749c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 750956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 751be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 75220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 75325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 754548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 75525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS(false) { 75619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 7578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 7581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 7591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 7601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 7611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 7621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 7631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 7641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 765c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 766c059860c73678a202bfa33062723e8f82fb779d9James Dong} 767c059860c73678a202bfa33062723e8f82fb779d9James Dong 768c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 769c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 770c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 771c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 772c059860c73678a202bfa33062723e8f82fb779d9James Dong 773c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 774c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 775c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 776c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 777c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 778c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 779c059860c73678a202bfa33062723e8f82fb779d9James Dong } 780c059860c73678a202bfa33062723e8f82fb779d9James Dong 781c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 782c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 783c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 784c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 785c059860c73678a202bfa33062723e8f82fb779d9James Dong } 786c059860c73678a202bfa33062723e8f82fb779d9James Dong 7878f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 78819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 78919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 79019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 79119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 79219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 79319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 79419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 79519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 79619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 79719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 79819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 79919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 80019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 80119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 80219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 80319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 80419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 80519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 80619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 80719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 80819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 80919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 81019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 81119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 81219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 81319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 81419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 81519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 81619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 81719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 81819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 81920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 82020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82120111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 82220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 82320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 82520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 82620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 82720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 82820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 82920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 83193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 83293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 83393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 83493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 83593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 83693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 83793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 83893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 83993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 84093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 84193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 84293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 84393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 84493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 8451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 8461c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 8471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 8481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 8491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 8501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 8511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 8521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8531c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 8541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 8551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 8561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 8571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 8591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 8601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 8621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 8631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 8641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 8651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 8691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 8701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8711c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeFirstChunk(ChunkInfo* info) { 8721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeFirstChunk: %p", info->mTrack); 8731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = info->mChunks.begin(); 8751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 8761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != chunkIt->mSamples.end(); ++it) { 8771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = info->mTrack->isAvc() 8791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ? addLengthPrefixedSample_l(*it) 8801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong : addSample_l(*it); 8811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it == chunkIt->mSamples.begin()) { 8821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mTrack->addChunkOffset(offset); 8831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Done with the current chunk. 8871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Release all the samples in this chunk. 8881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!chunkIt->mSamples.empty()) { 8891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 8901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 8911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 8921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.erase(it); 8931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 8941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.clear(); 8951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mChunks.erase(chunkIt); 8961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 8971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 8981c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeChunks() { 8991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeChunks"); 9001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 9011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mChunkInfos.empty()) { 9021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!it->mChunks.empty()) { 9041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(OK, writeOneChunk()); 9051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ++outstandingChunks; 9061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mTrack = NULL; 9081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.erase(it); 9091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 9111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 9121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9141c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::writeOneChunk() { 9151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeOneChunk"); 9161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Find the smallest timestamp, and write that chunk out 9181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // XXX: What if some track is just too slow? 9191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 9201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 9211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 9231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 9241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 9251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 9261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 9271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 9281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 9331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 9341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 9351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 9381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 9391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 9421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 9431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeFirstChunk(&(*it)); 9441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 9471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9491c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 9501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 9511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 9531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 9541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 9551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 9561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(writeOneChunk(), OK); 9571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 9611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Write ALL samples 9621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 9631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeChunks(); 9641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9671c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 9681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 9691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 9711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 972e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 9731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 9741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 9751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 9761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 9771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 9781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 9811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 9821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 9831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 9841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 9851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 9861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 98893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 989a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 990a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 991a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 992a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 993a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 99425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 99593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 99619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 99719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 99819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 99919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 1000e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = true; 1001e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1002e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1003e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1004e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1005e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1006e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1007e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 100893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 100993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1010f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1011f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1012f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 101325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 101425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 101525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 101625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 101720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 101820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 101920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 102020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 102120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 102220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1023c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 102425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1025956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 102620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 102725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 102820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 102925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 103025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 103120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 103220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1033a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dongvoid MPEG4Writer::Track::pause() { 1034a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 1035a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1036a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 103720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::stop() { 103820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 103920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return; 104020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 104120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 104320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 104520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 104620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 104720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource->stop(); 104820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 104920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 105025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 105125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 105225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 105325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 105420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 105520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 105620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 105720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 105820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber track->threadEntry(); 105920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 106020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return NULL; 106120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 106220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1063548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber#include <ctype.h> 1064548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huberstatic void hexdump(const void *_data, size_t size) { 1065548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber const uint8_t *data = (const uint8_t *)_data; 1066548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t offset = 0; 1067548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber while (offset < size) { 1068548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("0x%04x ", offset); 1069548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1070548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t n = size - offset; 1071548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (n > 16) { 1072548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber n = 16; 1073548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1074548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1075548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < 16; ++i) { 1076548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (i == 8) { 1077548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1078548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1079548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1080548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (offset + i < size) { 1081548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%02x ", data[offset + i]); 1082548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 1083548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1084548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1085548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1086548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1087548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1088548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1089548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < n; ++i) { 1090548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (isprint(data[offset + i])) { 1091548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%c", data[offset + i]); 1092548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 1093548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("."); 1094548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1095548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1096548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1097548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("\n"); 1098548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1099548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber offset += 16; 1100548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1101548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber} 1102548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 11033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 11043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 11053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 11073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 11083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 11113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 11123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 11143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 11163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 11173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 11183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 11193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 11213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 11223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 11243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 11273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 11283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 11303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 11313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 11323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 11343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 11353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 11363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 11373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 11383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 11413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 11423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 11433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 11443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 11453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 11473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 11483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 11493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 11503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 11513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 11523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 11533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 11543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 11553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 11563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 11593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 11603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 11613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 11633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 11663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 11673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 11683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 11703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 11713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 11723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 11733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 11743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 11773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 11783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 11793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 11803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 11833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 11843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 11863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 11873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 11883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 11893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 11903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 11913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 11923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 11933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 11943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 11953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 11963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 11973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 11983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 11993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 12003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 12013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 12023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 12053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 12063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 12083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 12093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 12103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 12113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 12143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 12153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 12173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 12183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 12193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 12233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 12273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 12283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 12293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 12303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 12333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 12343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 12353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 12363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 12373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 12413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 12423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 12473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 12483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 12493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 12503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 12513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 12543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 12553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 12603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 12613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 12623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 12633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 12643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 12653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 12663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 12703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1271548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 127203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 127303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1274548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber // hexdump(data, size); 1275548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 127603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1277548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 127803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 127903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 128003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 12813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 12823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 128303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 128403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 128503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 12863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 12873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 12883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 128903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 129003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 12913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 129203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 129303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 129403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 12953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 12963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 129703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 129803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 12993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 13003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 13013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 13023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 130303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 130503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 130603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 3; // length size == 4 bytes 130703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 130803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 1; // length size == 2 bytes 130903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 131003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 13123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 13133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 13143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 13153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 13163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 13173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 13183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 13193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 13203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 13213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 13233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 13243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 13253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 13283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 13293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 13303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 13313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 13323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 13333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 13343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 13353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 13363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 13373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 13393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 13403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 13413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 134203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 134303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 134403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 134503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13468644c14618d30d9e57a69df40ed939986ebf02c4James Dongstatic bool collectStatisticalData() { 13478644c14618d30d9e57a69df40ed939986ebf02c4James Dong char value[PROPERTY_VALUE_MAX]; 13488644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (property_get("media.stagefright.record-stats", value, NULL) 13498644c14618d30d9e57a69df40ed939986ebf02c4James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 13508644c14618d30d9e57a69df40ed939986ebf02c4James Dong return true; 13518644c14618d30d9e57a69df40ed939986ebf02c4James Dong } 13528644c14618d30d9e57a69df40ed939986ebf02c4James Dong return false; 13538644c14618d30d9e57a69df40ed939986ebf02c4James Dong} 13548644c14618d30d9e57a69df40ed939986ebf02c4James Dong 135520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::threadEntry() { 135630ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 135713aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 135813aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 135913aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 136013aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 13618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 13628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1363c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1364c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 13658f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1366be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1367a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 13681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1369e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1370e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t wallClockTimeUs = 0; 1371e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t lastWallClockTimeUs = 0; 1372e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1373d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 13748644c14618d30d9e57a69df40ed939986ebf02c4James Dong bool collectStats = collectStatisticalData(); 137520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1376ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 13771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMaxWriteTimeUs = 0; 137893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 137920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 138093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 138120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 138220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 138320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 138413aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 138520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 138620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 138720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1388a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1389a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1390a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1391a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1392a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1393a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1394a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1395a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1396a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 139730ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 139830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 139903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 140003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 140103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1402548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1403548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 14041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 140503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 140603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 140703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 140803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1409be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 14101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 141103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 141203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 141303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 141403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 141503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 141603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 141730ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 141830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 141930ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 142030ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 142130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1422548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 142330ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 1424a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1425a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1426d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 1427d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 1428d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1429d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1430d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 1431d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 1432d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 1433d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 1434d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 1435d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 14361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 1437e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 14388644c14618d30d9e57a69df40ed939986ebf02c4James Dong size_t sampleSize; 14391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong sampleSize = mIsAvc 144003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 1441d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 4 144203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 1443d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 2 144403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 1445d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong : copy->range_length(); 1446050b28a593350047845a45a14cc5026221ac1620James Dong 1447d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 14488644c14618d30d9e57a69df40ed939986ebf02c4James Dong mEstimatedTrackSizeBytes += sampleSize; 1449d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 1450d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1451d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1452d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1453d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 1454d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1455d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1456d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1457d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1458050b28a593350047845a45a14cc5026221ac1620James Dong 1459d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 1460d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1461d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1462d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 1463d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1464d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 14658644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 1466f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 1467f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 14683c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 146948c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 1470a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 1471c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong previousPausedDurationUs += (timestampUs - mTrackDurationUs - lastDurationUs); 1472a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 1473a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1474a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1475a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 1476e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mIsRealTimeRecording && !mIsAudio) { 1477e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // The minor adjustment on the timestamp is heuristic/experimental 1478e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // We are adjusting the timestamp to reduce the fluctuation of the duration 1479e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // of neighboring samples. This in turn helps reduce the track header size, 1480e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // especially, the number of entries in the "stts" box. 1481e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1482e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t durationUs = timestampUs + mOwner->getDriftTimeUs() - lastTimestampUs; 1483e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t diffUs = (durationUs > lastDurationUs) 1484e259531ce59ab1f31de5a23124b22536f6a5a767James Dong ? durationUs - lastDurationUs 1485e259531ce59ab1f31de5a23124b22536f6a5a767James Dong : lastDurationUs - durationUs; 1486e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (diffUs <= 5000) { // XXX: Magic number 5ms 1487e259531ce59ab1f31de5a23124b22536f6a5a767James Dong timestampUs = lastTimestampUs + lastDurationUs; 1488e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } else { 1489e259531ce59ab1f31de5a23124b22536f6a5a767James Dong timestampUs += mOwner->getDriftTimeUs(); 1490e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1491e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1492e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1493e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 1494e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1495e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 1496e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGW("Drop a frame, since it arrives too late!"); 1497e259531ce59ab1f31de5a23124b22536f6a5a767James Dong copy->release(); 1498e259531ce59ab1f31de5a23124b22536f6a5a767James Dong copy = NULL; 1499e259531ce59ab1f31de5a23124b22536f6a5a767James Dong continue; 1500e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1501e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1502e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1503a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong LOGV("time stamp: %lld and previous paused duration %lld", 1504a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs, previousPausedDurationUs); 1505c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 1506c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 15073b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 15083b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 15098644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 1510ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 1511ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 1512c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 1513c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 1514c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 1515c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 1516c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 1517c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 1518c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 1519c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 1520c059860c73678a202bfa33062723e8f82fb779d9James Dong 1521c059860c73678a202bfa33062723e8f82fb779d9James Dong if (currDurationTicks != lastDurationTicks) { 15228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1523be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 1524be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 1525be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1526be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 1527be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1528be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1529be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1530ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 1531be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 1532be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 15338644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 1534be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 15358644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 1536c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 15378644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 1538e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mIsRealTimeRecording && mIsAudio) { 1539e259531ce59ab1f31de5a23124b22536f6a5a767James Dong wallClockTimeUs = systemTime() / 1000; 1540e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t wallClockDurationUs = wallClockTimeUs - lastWallClockTimeUs; 1541e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 2) { 1542e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mOwner->addDriftTimeUs(lastDurationUs - wallClockDurationUs); 1543e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1544e259531ce59ab1f31de5a23124b22536f6a5a767James Dong lastWallClockTimeUs = wallClockTimeUs; 1545e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 154620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1547d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 1548ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mStssTableEntries.push_back(mNumSamples); 1549d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 1550d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 155193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 155293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 155393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 155493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 1555faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 155693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 155758ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 15581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 155958ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 156058ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 156158ae9c530247668f8af36e30d228c716c226b3d4James Dong mChunkOffsets.push_back(offset); 156258ae9c530247668f8af36e30d228c716c226b3d4James Dong } 156358ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 156458ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 156558ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 156658ae9c530247668f8af36e30d228c716c226b3d4James Dong } 156713aec890216948b0c364f8f92792129d0335f506James Dong 156813aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 156913aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 157013aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(++nChunks, 1, 1); 157113aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 15721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 157313aec890216948b0c364f8f92792129d0335f506James Dong } else { 157413aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 157513aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 157613aec890216948b0c364f8f92792129d0335f506James Dong } else { 157713aec890216948b0c364f8f92792129d0335f506James Dong if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 157813aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 15798644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (collectStats) { 15808644c14618d30d9e57a69df40ed939986ebf02c4James Dong mChunkDurations.push_back(timestampUs - chunkTimestampUs); 15818644c14618d30d9e57a69df40ed939986ebf02c4James Dong } 158213aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 158313aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 158413aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 158513aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, 158613aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size(), 1); 158713aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 158813aec890216948b0c364f8f92792129d0335f506James Dong } 15891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 159013aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 159113aec890216948b0c364f8f92792129d0335f506James Dong } 159213aec890216948b0c364f8f92792129d0335f506James Dong } 159313aec890216948b0c364f8f92792129d0335f506James Dong } 159413aec890216948b0c364f8f92792129d0335f506James Dong 159520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 159625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 15978644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 159893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong err = UNKNOWN_ERROR; 1599f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 1600faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, -1, err); 1601be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 160213aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 160358ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 1604ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong StscTableEntry stscEntry(1, mNumSamples, 1); 160558ae9c530247668f8af36e30d228c716c226b3d4James Dong mStscTableEntries.push_back(stscEntry); 160658ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 160713aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 160813aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1); 160913aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 16101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 161113aec890216948b0c364f8f92792129d0335f506James Dong } 161213aec890216948b0c364f8f92792129d0335f506James Dong 1613be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 1614be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 1615be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 1616ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 16178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 1618be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1619be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 1620be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 16218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1622be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 1623c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 162425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 16251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. Max write time: %lld us - %s", 16261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong count, nZeroLengthFrames, mNumSamples, mMaxWriteTimeUs, mIsAudio? "audio": "video"); 1627365a963142093a1cd8efdcea76b5f65096a5b115James Dong 16281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong logStatisticalData(mIsAudio); 1629365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1630365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1631faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 1632faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 1633215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 1634215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 163593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 1636faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err); 163793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 163893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 163993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 164093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1641faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 1642faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong const MPEG4Writer::Track* track, int64_t timeUs, status_t err) { 1643faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 1644faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t nTracks = mTracks.size(); 1645faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks >= 1); 1646faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks < 64); // Arbitrary number 1647faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1648faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t trackNum = 0; 1649faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#if 0 1650faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // In the worst case, we can put the trackNum 1651faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // along with MEDIA_RECORDER_INFO_COMPLETION_STATUS 1652faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // to report the progress. 1653faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong for (List<Track *>::iterator it = mTracks.begin(); 1654faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong it != mTracks.end(); ++it, ++trackNum) { 1655faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (track == (*it)) { 1656faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong break; 1657faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1658faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1659faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#endif 1660faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(trackNum < nTracks); 1661faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum <<= 16; 1662faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1663faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 1664faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 1665faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 1666faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_ERROR, 1667faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_ERROR_UNKNOWN, 1668faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 1669faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 1670faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1671faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1672faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 1673faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 1674faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 1675faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS, 1676faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 1677faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 1678faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 1679faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 1680faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 1681faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, 1682faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 1683faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1684faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 1685faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1686215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dongvoid MPEG4Writer::Track::findMinAvgMaxSampleDurationMs( 1687215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t *min, int32_t *avg, int32_t *max) { 16888644c14618d30d9e57a69df40ed939986ebf02c4James Dong CHECK(!mSampleSizes.empty()); 1689c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int32_t avgSampleDurationMs = mTrackDurationUs / 1000 / mNumSamples; 1690215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t minSampleDurationMs = 0x7FFFFFFF; 1691215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t maxSampleDurationMs = 0; 1692365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1693365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != mSttsTableEntries.end(); ++it) { 16948f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleDurationMs = 16958f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000; 1696215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (sampleDurationMs > maxSampleDurationMs) { 1697215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong maxSampleDurationMs = sampleDurationMs; 1698215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong } else if (sampleDurationMs < minSampleDurationMs) { 1699215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong minSampleDurationMs = sampleDurationMs; 1700365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1701215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("sample duration: %d ms", sampleDurationMs); 1702365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1703215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(minSampleDurationMs != 0); 1704215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(avgSampleDurationMs != 0); 1705215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(maxSampleDurationMs != 0); 1706215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *min = minSampleDurationMs; 1707215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *avg = avgSampleDurationMs; 1708215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *max = maxSampleDurationMs; 1709365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1710365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1711365a963142093a1cd8efdcea76b5f65096a5b115James Dong// Don't count the last duration 1712365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) { 1713365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1714365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunkDuration = duration; 1715365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t maxChunkDuration = duration; 1716365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (mChunkDurations.size() > 1) { 1717365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<int64_t>::iterator it = mChunkDurations.begin(); 1718365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != --mChunkDurations.end(); ++it) { 1719365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (minChunkDuration > (*it)) { 1720365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunkDuration = (*it); 1721365a963142093a1cd8efdcea76b5f65096a5b115James Dong } else if (maxChunkDuration < (*it)) { 1722365a963142093a1cd8efdcea76b5f65096a5b115James Dong maxChunkDuration = (*it); 1723365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1724365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1725365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1726365a963142093a1cd8efdcea76b5f65096a5b115James Dong *min = minChunkDuration; 1727365a963142093a1cd8efdcea76b5f65096a5b115James Dong *max = maxChunkDuration; 1728365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1729365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1730365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::logStatisticalData(bool isAudio) { 1731c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (mTrackDurationUs <= 0 || mSampleSizes.empty()) { 1732365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("nothing is recorded"); 1733365a963142093a1cd8efdcea76b5f65096a5b115James Dong return; 1734365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1735365a963142093a1cd8efdcea76b5f65096a5b115James Dong 17368644c14618d30d9e57a69df40ed939986ebf02c4James Dong bool collectStats = collectStatisticalData(); 1737365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1738365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (collectStats) { 1739215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("%s track - duration %lld us, total %d frames", 1740c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong isAudio? "audio": "video", mTrackDurationUs, 1741ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples); 1742215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t min, avg, max; 1743215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong findMinAvgMaxSampleDurationMs(&min, &avg, &max); 1744215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max); 1745215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (!isAudio) { 1746215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float avgFps = 1000.0 / avg; 1747215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float minFps = 1000.0 / max; 1748215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float maxFps = 1000.0 / min; 1749365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f", 1750215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong minFps, avgFps, maxFps); 1751365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1752365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1753365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t totalBytes = 0; 17548644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 17558644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 17568644c14618d30d9e57a69df40ed939986ebf02c4James Dong totalBytes += (*it); 1757365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1758c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong float bitRate = (totalBytes * 8000000.0) / mTrackDurationUs; 1759365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("avg bit rate (bps): %.2f", bitRate); 1760365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1761365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1762365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (duration != 0) { // If interleaving is enabled 1763365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunk, maxChunk; 1764365a963142093a1cd8efdcea76b5f65096a5b115James Dong findMinMaxChunkDurations(&minChunk, &maxChunk); 1765365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld", 1766365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunk, duration, maxChunk); 1767365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1768365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 176913aec890216948b0c364f8f92792129d0335f506James Dong} 177013aec890216948b0c364f8f92792129d0335f506James Dong 1771e259531ce59ab1f31de5a23124b22536f6a5a767James Dongvoid MPEG4Writer::addDriftTimeUs(int64_t driftTimeUs) { 1772e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("addDriftTimeUs: %lld us", driftTimeUs); 1773e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 1774e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs += driftTimeUs; 1775e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 1776e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1777e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 1778e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 1779e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 1780e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 1781e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 1782e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 17831c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 17841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 17851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 17861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t startTimeUs = systemTime() / 1000; 17871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 17881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 178913aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 17901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t endTimeUs = systemTime() / 1000; 17911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mMaxWriteTimeUs < endTimeUs - startTimeUs) { 17921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMaxWriteTimeUs = endTimeUs - startTimeUs; 17931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 179420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 179520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 17963b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 1797c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 179820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 179920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1800d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 1801d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 1802d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1803d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 18041acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader( 18051acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t trackID, bool use32BitOffset) { 180620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 180720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 18080c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 180920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18108f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 18111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 18128f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 181320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 18148f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 18158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 181620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 181720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 181820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 181920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 18201acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Flags = 7 to indicate that the track is enabled, and 18211acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // part of the presentation 18221acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x07); // version=0, flags=7 182320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 182420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 182520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 182620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 18278f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t tkhdDuration = 18288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 18298f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 183020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 183120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 183220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 183320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 18341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 183520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 183620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 183720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); // matrix 183820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 183920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 184020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 184120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); 184220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 184320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 184420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 184520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x40000000); 184620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 184820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 184920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 185020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 185120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 185220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 185320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 18540c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 185520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1856050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 1857050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 185820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 185920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 186020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1861f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 1862f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong if (mStartTimestampUs != moovStartTimeUs) { 18633c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("edts"); 18643c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("elst"); 18651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 18661acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(2); // never ends with an empty list 18678f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 18688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // First elst entry: specify the starting time offset 18698f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; 18708f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; 18718f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timecale 18728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(-1); // starting time offset 18738f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(1 << 16); // rate = 1.0 18748f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 18758f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // Second elst entry: specify the track duration 18768f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 18778f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timescale 18781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); 18791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); 18803c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 18813c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 18823c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 18833c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 188420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 188520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 188620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 188720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 188820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 188920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 18908f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mTimeScale); // media timescale 18918f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 18928f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mdhdDuration); // use media timescale 18931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Language follows the three letter standard ISO-639-2/T 18941acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // 'e', 'n', 'g' for "English", for instance. 18951acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Each character is packed as the difference between its ASCII value and 0x60. 18961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // For "English", these are 00101, 01110, 00111. 18971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // XXX: Where is the padding bit located: 0x15C7? 18981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(0); // language code 189920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 190020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 190120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 190220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 190320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 1904050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // component type: should be mhlr 19051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 190620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 190720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 190820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 19091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Removing "r" for the name string just makes the string 4 byte aligned 19101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 191120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 191220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 191320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 19141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 191520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 191620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 191720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 191820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 191920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 192020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 192120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 19221acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x01); // version=0, flags=1 192320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 192420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 192520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 192620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 192720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 192820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 1929050b28a593350047845a45a14cc5026221ac1620James Dong 1930050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dinf"); 1931050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dref"); 1932050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 19331acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // entry count (either url or urn) 19341acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // The table index here refers to the sample description index 19351acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // in the sample table entries. 1936050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("url "); 19371acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 1938050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // url 1939050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dref 1940050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dinf 1941050b28a593350047845a45a14cc5026221ac1620James Dong 194220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 194320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 194420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 194520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 194620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 19471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 194825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 194918291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 195025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 195118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 195225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 1953050b28a593350047845a45a14cc5026221ac1620James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1954050b28a593350047845a45a14cc5026221ac1620James Dong fourcc = "mp4a"; 195525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 195625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 195725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 195825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 195925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 196025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 196120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 196220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 1963050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x1); // data ref index 196420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 196520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 1966050b28a593350047845a45a14cc5026221ac1620James Dong int32_t nChannels; 1967050b28a593350047845a45a14cc5026221ac1620James Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 1968050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(nChannels); // channel count 196920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 197020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 197120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 197220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 197320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 197420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 19750c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 197620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 197720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 1978050b28a593350047845a45a14cc5026221ac1620James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1979050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("esds"); 198051dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 198151dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 1982050b28a593350047845a45a14cc5026221ac1620James Dong 1983050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 1984050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x03); // ES_DescrTag 1985050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 1986050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x0000);// ES_ID 1987050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); 1988050b28a593350047845a45a14cc5026221ac1620James Dong 1989050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 1990050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 1991050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 1992050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x15); // streamType AudioStream 1993050b28a593350047845a45a14cc5026221ac1620James Dong 1994050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x03); // XXX 1995050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); // buffer size 24-bit 1996050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // max bit rate 1997050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // avg bit rate 1998050b28a593350047845a45a14cc5026221ac1620James Dong 1999050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2000050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(mCodecSpecificDataSize); 2001050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2002050b28a593350047845a45a14cc5026221ac1620James Dong 2003050b28a593350047845a45a14cc5026221ac1620James Dong static const uint8_t kData2[] = { 2004050b28a593350047845a45a14cc5026221ac1620James Dong 0x06, // SLConfigDescriptorTag 2005050b28a593350047845a45a14cc5026221ac1620James Dong 0x01, 2006050b28a593350047845a45a14cc5026221ac1620James Dong 0x02 2007050b28a593350047845a45a14cc5026221ac1620James Dong }; 2008050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(kData2, sizeof(kData2)); 2009050b28a593350047845a45a14cc5026221ac1620James Dong 2010050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // esds 20115aff464f67322cd13dc8ed165806971cfff2e4d5James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 20125aff464f67322cd13dc8ed165806971cfff2e4d5James Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 20135aff464f67322cd13dc8ed165806971cfff2e4d5James Dong // 3gpp2 Spec AMRSampleEntry fields 20145aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->beginBox("damr"); 20155aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeCString(" "); // vendor: 4 bytes 20165aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // decoder version 20175aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 20185aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // mode change period 20195aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(1); // frames per sample 20205aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->endBox(); 2021050b28a593350047845a45a14cc5026221ac1620James Dong } 202220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 202320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 202418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 202520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 202618291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 202720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 202830ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 202930ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 203020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 203125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 20320c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 203320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 203420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 203520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 203620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 20371acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(1); // data ref index 203820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 203920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 204020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 204120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 204220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 204320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 204420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 204520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 204620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 20470c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 204820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 204920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 205020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 205120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 205220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 205320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 205420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 205520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 205620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 205720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 205820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 20590c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 206020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 206118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2062a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificData); 2063a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificDataSize > 0); 206420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 206520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 206620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 206720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 206820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 206920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 207020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 207120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 207220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 207320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 207420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 207520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 207620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 207720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 207820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 207920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 208020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 208120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 208220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 208320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 2084050b28a593350047845a45a14cc5026221ac1620James Dong 208520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 208620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 208720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 208820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 208920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 209020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 209120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 209220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 209320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 209420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 209520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 209620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 209720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 209818291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 209920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 210020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 210120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 210220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 210320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 210420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 210520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 210620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 210730ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 210851dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 210951dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 211030ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 211130ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 211230ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 211320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 211430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 21151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox("pasp"); 21161acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // This is useful if the pixel is not square 21171acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // hspacing 21181acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // vspacing 21191acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // pasp 212030ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 212120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 212220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 212320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 212420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 212520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2126be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(mSttsTableEntries.size()); 2127c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t prevTimestampUs = 0; 2128be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 2129be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSttsTableEntries.end(); ++it) { 2130be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleCount); 2131c059860c73678a202bfa33062723e8f82fb779d9James Dong 2132c059860c73678a202bfa33062723e8f82fb779d9James Dong // Make sure that we are calculating the sample duration the exactly 2133c059860c73678a202bfa33062723e8f82fb779d9James Dong // same way as we made decision on how to create stts entries. 2134c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; 2135c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - 2136c059860c73678a202bfa33062723e8f82fb779d9James Dong (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2137c059860c73678a202bfa33062723e8f82fb779d9James Dong prevTimestampUs += (it->sampleCount * it->sampleDurationUs); 2138c059860c73678a202bfa33062723e8f82fb779d9James Dong 21398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(dur); 214020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 214120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 214220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!mIsAudio) { 2144050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("stss"); 2145050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2146050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames 2147050b28a593350047845a45a14cc5026221ac1620James Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2148050b28a593350047845a45a14cc5026221ac1620James Dong it != mStssTableEntries.end(); ++it) { 2149050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(*it); 2150050b28a593350047845a45a14cc5026221ac1620James Dong } 2151050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // stss 2152050b28a593350047845a45a14cc5026221ac1620James Dong } 2153050b28a593350047845a45a14cc5026221ac1620James Dong 215420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 215520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2156be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 21578644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t>::iterator it = mSampleSizes.begin(); 21588644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); // default sample size 2159be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2160be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(0); 2161be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2162ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mOwner->writeInt32(mNumSamples); 2163be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (!mSamplesHaveSameSize) { 21648644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 21658644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 21668644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); 2167be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 216820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 216920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 217020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 217120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 217220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 217313aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mStscTableEntries.size()); 217413aec890216948b0c364f8f92792129d0335f506James Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 217513aec890216948b0c364f8f92792129d0335f506James Dong it != mStscTableEntries.end(); ++it) { 217613aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->firstChunk); 217713aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->samplesPerChunk); 217813aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->sampleDescriptionId); 217920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 218020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 21811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 218220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 218313aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mChunkOffsets.size()); 218413aec890216948b0c364f8f92792129d0335f506James Dong for (List<off_t>::iterator it = mChunkOffsets.begin(); 218513aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkOffsets.end(); ++it) { 21861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (use32BitOffset) { 21871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 21881acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 21891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt64((*it)); 21901acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 219120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 21928f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->endBox(); // stco or co64 219320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 219420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 21951acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // minf 219620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 219720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 219820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 219920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 220020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2201