MPEG4Writer.cpp revision d707fcb3e29707ca4a5935c294ef0b38eb5aba5f
120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber/* 220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Copyright (C) 2009 The Android Open Source Project 320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * you may not use this file except in compliance with the License. 620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * You may obtain a copy of the License at 720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * 1020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Unless required by applicable law or agreed to in writing, software 1120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 1220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * See the License for the specific language governing permissions and 1420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * limitations under the License. 1520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber */ 1620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 17050b28a593350047845a45a14cc5026221ac1620James Dong//#define LOG_NDEBUG 0 18050b28a593350047845a45a14cc5026221ac1620James Dong#define LOG_TAG "MPEG4Writer" 19050b28a593350047845a45a14cc5026221ac1620James Dong#include <utils/Log.h> 20050b28a593350047845a45a14cc5026221ac1620James Dong 2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h> 2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <ctype.h> 2420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h> 2520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 290c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h> 3018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 3103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 34d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h> 35365a963142093a1cd8efdcea76b5f65096a5b115James Dong#include <cutils/properties.h> 3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h" 3819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07; 423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08; 433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 4625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track(MPEG4Writer *owner, const sp<MediaSource> &source); 478f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 4820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 4920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t start(MetaData *params); 5137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t stop(); 5237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t pause(); 5325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 553b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 56d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t getEstimatedTrackSizeBytes() const; 571acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); 581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void bufferChunk(int64_t timestampUs); 591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAvc() const { return mIsAvc; } 601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isAudio() const { return mIsAudio; } 611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool isMPEG4() const { return mIsMPEG4; } 621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void addChunkOffset(off_t offset) { mChunkOffsets.push_back(offset); } 63dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong status_t dump(int fd, const Vector<String16>& args) const; 6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 6620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 6720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 68693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 6920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 70a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mPaused; 71a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong volatile bool mResumed; 721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAvc; 731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsAudio; 741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bool mIsMPEG4; 75c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int64_t mTrackDurationUs; 76e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 77e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // For realtime applications, we need to adjust the media clock 78e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // for video track based on the audio media clock 79e259531ce59ab1f31de5a23124b22536f6a5a767James Dong bool mIsRealTimeRecording; 80e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t mMaxTimeStampUs; 81d599cd4573b5a2d5914c5040e0565ef866749b77James Dong int64_t mEstimatedTrackSizeBytes; 821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t mMaxWriteTimeUs; 838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mTimeScale; 8420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 8620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 87ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // mNumSamples is used to track how many samples in mSampleSizes List. 88ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // This is to reduce the cost associated with mSampleSizes.size() call, 89ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong // since it is O(n). Ideally, the fix should be in List class. 90ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong size_t mNumSamples; 918644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t> mSampleSizes; 92be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong bool mSamplesHaveSameSize; 93be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 9413aec890216948b0c364f8f92792129d0335f506James Dong List<MediaBuffer *> mChunkSamples; 9513aec890216948b0c364f8f92792129d0335f506James Dong List<off_t> mChunkOffsets; 9613aec890216948b0c364f8f92792129d0335f506James Dong 9713aec890216948b0c364f8f92792129d0335f506James Dong struct StscTableEntry { 9813aec890216948b0c364f8f92792129d0335f506James Dong 9913aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 10013aec890216948b0c364f8f92792129d0335f506James Dong : firstChunk(chunk), 10113aec890216948b0c364f8f92792129d0335f506James Dong samplesPerChunk(samples), 10213aec890216948b0c364f8f92792129d0335f506James Dong sampleDescriptionId(id) {} 10313aec890216948b0c364f8f92792129d0335f506James Dong 10413aec890216948b0c364f8f92792129d0335f506James Dong uint32_t firstChunk; 10513aec890216948b0c364f8f92792129d0335f506James Dong uint32_t samplesPerChunk; 10613aec890216948b0c364f8f92792129d0335f506James Dong uint32_t sampleDescriptionId; 10713aec890216948b0c364f8f92792129d0335f506James Dong }; 10813aec890216948b0c364f8f92792129d0335f506James Dong List<StscTableEntry> mStscTableEntries; 10920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 110050b28a593350047845a45a14cc5026221ac1620James Dong List<int32_t> mStssTableEntries; 111365a963142093a1cd8efdcea76b5f65096a5b115James Dong List<int64_t> mChunkDurations; 112050b28a593350047845a45a14cc5026221ac1620James Dong 113be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong struct SttsTableEntry { 114be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry(uint32_t count, uint32_t durationUs) 1168f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong : sampleCount(count), sampleDurationUs(durationUs) {} 117be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 118be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t sampleCount; 1198f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong uint32_t sampleDurationUs; 120be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong }; 121be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong List<SttsTableEntry> mSttsTableEntries; 122be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 1233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Sequence parameter set or picture parameter set 1243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong struct AVCParamSet { 1253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet(uint16_t length, const uint8_t *data) 1263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong : mLength(length), mData(data) {} 1273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 1283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t mLength; 1293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *mData; 1303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong }; 1313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mSeqParamSets; 1323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong List<AVCParamSet> mPicParamSets; 1333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileIdc; 1343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mProfileCompatible; 1353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t mLevelIdc; 1363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 13820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 139548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber bool mGotAllCodecSpecificData; 14093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong bool mTrackingProgressStatus; 14120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 14225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 1433c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong int64_t mStartTimestampUs; 14493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mPreviousTrackTimeUs; 14593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t mTrackEveryTimeDurationUs; 14625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 14720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 14837187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t threadEntry(); 14920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *parseParamSet( 1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen); 1523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 15303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t makeAVCCodecSpecificData( 15403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size); 1553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t copyAVCCodecSpecificData( 1563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 1573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong status_t parseAVCCodecSpecificData( 1583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size); 159215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 160215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Track authoring progress status 161faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong void trackProgressStatus(int64_t timeUs, status_t err = OK); 16293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong void initTrackingProgressStatus(MetaData *params); 16303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 164215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong // Utilities for collecting statistical data 165215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong void logStatisticalData(bool isAudio); 166215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong void findMinAvgMaxSampleDurationMs( 167215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t *min, int32_t *avg, int32_t *max); 168215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong void findMinMaxChunkDurations(int64_t *min, int64_t *max); 169215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong 17019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber void getCodecSpecificDataFromInputFormatIfPossible(); 17119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 172c059860c73678a202bfa33062723e8f82fb779d9James Dong // Determine the track time scale 173c059860c73678a202bfa33062723e8f82fb779d9James Dong // If it is an audio track, try to use the sampling rate as 174c059860c73678a202bfa33062723e8f82fb779d9James Dong // the time scale; however, if user chooses the overwrite 175c059860c73678a202bfa33062723e8f82fb779d9James Dong // value, the user-supplied time scale will be used. 176c059860c73678a202bfa33062723e8f82fb779d9James Dong void setTimeScale(); 177c059860c73678a202bfa33062723e8f82fb779d9James Dong 178690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Simple validation on the codec specific data 179690f546b0ee548dbfe997df36418e5302ec2d786James Dong status_t checkCodecSpecificData() const; 180690f546b0ee548dbfe997df36418e5302ec2d786James Dong 18120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 18220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 18320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#define USE_NALLEN_FOUR 1 18603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 18720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 18820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mFile(fopen(filename, "wb")), 1891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 190a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 191a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 19220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 19313aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 1947837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 195f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 1960c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mFile != NULL); 19720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 19820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19930ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 20030ab66297501757d745b9ae10da61adcd891f497Andreas Huber : mFile(fdopen(fd, "wb")), 2011acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mUse32BitOffset(true), 202a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 203a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted(false), 20430ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 20513aec890216948b0c364f8f92792129d0335f506James Dong mMdatOffset(0), 2067837c17063a4c50bc856ba59418516fdab731de7James Dong mEstimatedMoovBoxSize(0), 207f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong mInterleaveDurationUs(1000000) { 20830ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(mFile != NULL); 20930ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 21030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 21120111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 21220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 21520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 21620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 21720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 22020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 221dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump( 222dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) { 223dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 224dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 225dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 226dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 227dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 228dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 229dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 230dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 231dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong for (List<Track *>::iterator it = mTracks.begin(); 232dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong it != mTracks.end(); ++it) { 233dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong (*it)->dump(fd, args); 234dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong } 235dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 236dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 237dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 238dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump( 239dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong int fd, const Vector<String16>& args) const { 240dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong const size_t SIZE = 256; 241dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong char buffer[SIZE]; 242dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong String8 result; 243dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 244dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 245dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong snprintf(buffer, SIZE, " reached EOS: %s\n", 246dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong mReachedEOS? "true": "false"); 247dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong result.append(buffer); 248dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong ::write(fd, result.string(), result.size()); 249dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong return OK; 250dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong} 251dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong 2522dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 25325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track *track = new Track(this, source); 25420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 2552dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 2562dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 25720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 25820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 25993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) { 260a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 261a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 26293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = (*it)->start(params); 263a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 264a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 265a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it2 = mTracks.begin(); 266a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it2 != it; ++it2) { 267a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong (*it2)->stop(); 268a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 269a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 270a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 271a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 272a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 273a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 274a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 275a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 2762dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 2772dec2b5be2056c6d9428897dc672185872d30d17James Dong // This implementation is highly experimental/heurisitic. 2782dec2b5be2056c6d9428897dc672185872d30d17James Dong // 2792dec2b5be2056c6d9428897dc672185872d30d17James Dong // Statistical analysis shows that metadata usually accounts 2802dec2b5be2056c6d9428897dc672185872d30d17James Dong // for a small portion of the total file size, usually < 0.6%. 2812dec2b5be2056c6d9428897dc672185872d30d17James Dong // Currently, lets set to 0.4% for now. 2822dec2b5be2056c6d9428897dc672185872d30d17James Dong 2832dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB, 2842dec2b5be2056c6d9428897dc672185872d30d17James Dong // where 1MB is the common file size limit for MMS application. 2852dec2b5be2056c6d9428897dc672185872d30d17James Dong // The default MAX _MOOV_BOX_SIZE value is based on about 4 2862dec2b5be2056c6d9428897dc672185872d30d17James Dong // minute video recording with a bit rate about 3 Mbps, because 2872dec2b5be2056c6d9428897dc672185872d30d17James Dong // statistics also show that most of the video captured are going 2882dec2b5be2056c6d9428897dc672185872d30d17James Dong // to be less than 3 minutes. 2892dec2b5be2056c6d9428897dc672185872d30d17James Dong 2902dec2b5be2056c6d9428897dc672185872d30d17James Dong // If the estimation is wrong, we will pay the price of wasting 2912dec2b5be2056c6d9428897dc672185872d30d17James Dong // some reserved space. This should not happen so often statistically. 2922dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int32_t factor = mUse32BitOffset? 1: 2; 2932dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024; // 4 KB 2942dec2b5be2056c6d9428897dc672185872d30d17James Dong static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 2952dec2b5be2056c6d9428897dc672185872d30d17James Dong int64_t size = MIN_MOOV_BOX_SIZE; 2962dec2b5be2056c6d9428897dc672185872d30d17James Dong 2972dec2b5be2056c6d9428897dc672185872d30d17James Dong if (mMaxFileSizeLimitBytes != 0) { 2982dec2b5be2056c6d9428897dc672185872d30d17James Dong size = mMaxFileSizeLimitBytes * 4 / 1000; 2992dec2b5be2056c6d9428897dc672185872d30d17James Dong } else if (mMaxFileDurationLimitUs != 0) { 3002dec2b5be2056c6d9428897dc672185872d30d17James Dong if (bitRate <= 0) { 3012dec2b5be2056c6d9428897dc672185872d30d17James Dong // We could not estimate the file size since bitRate is not set. 3022dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 3032dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 3042dec2b5be2056c6d9428897dc672185872d30d17James Dong size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000); 3052dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3062dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3072dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size < MIN_MOOV_BOX_SIZE) { 3082dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MIN_MOOV_BOX_SIZE; 3092dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3102dec2b5be2056c6d9428897dc672185872d30d17James Dong 3112dec2b5be2056c6d9428897dc672185872d30d17James Dong // Any long duration recording will be probably end up with 3122dec2b5be2056c6d9428897dc672185872d30d17James Dong // non-streamable mp4 file. 3132dec2b5be2056c6d9428897dc672185872d30d17James Dong if (size > MAX_MOOV_BOX_SIZE) { 3142dec2b5be2056c6d9428897dc672185872d30d17James Dong size = MAX_MOOV_BOX_SIZE; 3152dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3162dec2b5be2056c6d9428897dc672185872d30d17James Dong 3172dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 3182dec2b5be2056c6d9428897dc672185872d30d17James Dong " moov size %lld bytes", 3192dec2b5be2056c6d9428897dc672185872d30d17James Dong mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 3202dec2b5be2056c6d9428897dc672185872d30d17James Dong return factor * size; 3212dec2b5be2056c6d9428897dc672185872d30d17James Dong} 3222dec2b5be2056c6d9428897dc672185872d30d17James Dong 3232dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) { 32420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 32525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 32620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 32720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3282dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t use64BitOffset; 3292dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param && 3302dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 3312dec2b5be2056c6d9428897dc672185872d30d17James Dong use64BitOffset) { 3322dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 3332dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3342dec2b5be2056c6d9428897dc672185872d30d17James Dong 3352dec2b5be2056c6d9428897dc672185872d30d17James Dong // System property can overwrite the file offset bits parameter 3362dec2b5be2056c6d9428897dc672185872d30d17James Dong char value[PROPERTY_VALUE_MAX]; 3372dec2b5be2056c6d9428897dc672185872d30d17James Dong if (property_get("media.stagefright.record-64bits", value, NULL) 3382dec2b5be2056c6d9428897dc672185872d30d17James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 3392dec2b5be2056c6d9428897dc672185872d30d17James Dong mUse32BitOffset = false; 3402dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3412dec2b5be2056c6d9428897dc672185872d30d17James Dong 342065d1aff96818df54456053f1574aec8a234d0deJames Dong mStartTimestampUs = -1; 34393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 344a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mStarted) { 345a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused) { 346a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 34793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong return startTracks(param); 348a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 349a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 350a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 351a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 3528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (!param || 3538f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong !param->findInt32(kKeyTimeScale, &mTimeScale)) { 3548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mTimeScale = 1000; 3558f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong } 3568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 3578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("movie time scale: %d", mTimeScale); 3588f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 3597837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = true; 3607837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 3617837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 3627837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 3637837c17063a4c50bc856ba59418516fdab731de7James Dong 36420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 36593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 36693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int32_t fileType; 36793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (param && param->findInt32(kKeyFileType, &fileType) && 36893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong fileType != OUTPUT_FORMAT_MPEG_4) { 36993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 37093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } else { 37193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("isom"); 37293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 37393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 37420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 37520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 37693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong writeFourcc("3gp4"); 37720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 37820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3797837c17063a4c50bc856ba59418516fdab731de7James Dong mFreeBoxOffset = mOffset; 38020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3817837c17063a4c50bc856ba59418516fdab731de7James Dong if (mEstimatedMoovBoxSize == 0) { 3822dec2b5be2056c6d9428897dc672185872d30d17James Dong int32_t bitRate = -1; 3832dec2b5be2056c6d9428897dc672185872d30d17James Dong if (param) { 3842dec2b5be2056c6d9428897dc672185872d30d17James Dong param->findInt32(kKeyBitRate, &bitRate); 3852dec2b5be2056c6d9428897dc672185872d30d17James Dong } 3862dec2b5be2056c6d9428897dc672185872d30d17James Dong mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 3877837c17063a4c50bc856ba59418516fdab731de7James Dong } 3887837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mEstimatedMoovBoxSize >= 8); 3897837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 3907837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize); 3917837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 3927837c17063a4c50bc856ba59418516fdab731de7James Dong 3937837c17063a4c50bc856ba59418516fdab731de7James Dong mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 3947837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mMdatOffset; 3957837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 3961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 3971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("????mdat", 8); 3981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 3991acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong write("\x00\x00\x00\x01mdat????????", 16); 4001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 4011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong status_t err = startWriterThread(); 4031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (err != OK) { 4041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return err; 4051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 4061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong err = startTracks(param); 408a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (err != OK) { 409a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return err; 41020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 4111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 412a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = true; 41325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 41420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 41520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 41637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() { 417a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mFile == NULL) { 41837187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 419a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 420a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 42137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 422a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong for (List<Track *>::iterator it = mTracks.begin(); 423a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong it != mTracks.end(); ++it) { 42437187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->pause(); 42537187916a486504acaf83bea30147eb5fbf46ae5James Dong if (status != OK) { 42637187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 42737187916a486504acaf83bea30147eb5fbf46ae5James Dong } 428a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 42937187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 430a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 431a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 4321c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() { 4331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("stopWriterThread"); 4341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 4361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 4371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = true; 4391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 4401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 4411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 4421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong void *dummy; 4431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_join(mThread, &dummy); 4441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 4451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 44637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() { 44720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 44837187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 44920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 45020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 45137187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = OK; 4528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t maxDurationUs = 0; 45320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 45420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 45537187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = (*it)->stop(); 45637187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK) { 45737187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 45837187916a486504acaf83bea30147eb5fbf46ae5James Dong } 45920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t durationUs = (*it)->getDurationUs(); 4618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong if (durationUs > maxDurationUs) { 4628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong maxDurationUs = durationUs; 46320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 46420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 46520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong stopWriterThread(); 4677837c17063a4c50bc856ba59418516fdab731de7James Dong 46837187916a486504acaf83bea30147eb5fbf46ae5James Dong // Do not write out movie header on error. 46937187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err != OK) { 47037187916a486504acaf83bea30147eb5fbf46ae5James Dong fflush(mFile); 47137187916a486504acaf83bea30147eb5fbf46ae5James Dong fclose(mFile); 47237187916a486504acaf83bea30147eb5fbf46ae5James Dong mFile = NULL; 47337187916a486504acaf83bea30147eb5fbf46ae5James Dong mStarted = false; 47437187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 47537187916a486504acaf83bea30147eb5fbf46ae5James Dong } 47637187916a486504acaf83bea30147eb5fbf46ae5James Dong 47720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 4781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (mUse32BitOffset) { 4791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset, SEEK_SET); 4801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 4811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 4, mFile); 4821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 4831acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fseeko(mFile, mMdatOffset + 8, SEEK_SET); 4841acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int64_t size = mOffset - mMdatOffset; 4851acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong size = hton64(size); 4861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong fwrite(&size, 1, 8, mFile); 4871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 4887837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 48920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 49020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 4917837c17063a4c50bc856ba59418516fdab731de7James Dong const off_t moovOffset = mOffset; 4927837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = true; 4937837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 4947837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 4957837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBuffer != NULL); 496c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6; 49720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 49820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 49920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 50020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 50120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 50220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 50320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 5048f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong writeInt32(mTimeScale); // mvhd timescale 5051acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(duration); 5061acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong writeInt32(0x10000); // rate: 1.0 50720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 50820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 50920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 51020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 51120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); // matrix 51220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 51320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 51420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 51520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); 51620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 51720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 51820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 51920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x40000000); 52020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 52120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 52220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 52320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 52420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 52520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 52620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 52720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 53020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 53120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 5321acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong (*it)->writeTrackHeader(id, mUse32BitOffset); 53320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 53420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 53520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5367837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 5377837c17063a4c50bc856ba59418516fdab731de7James Dong if (mStreamableFile) { 5387837c17063a4c50bc856ba59418516fdab731de7James Dong CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 5397837c17063a4c50bc856ba59418516fdab731de7James Dong 5407837c17063a4c50bc856ba59418516fdab731de7James Dong // Moov box 5417837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mFreeBoxOffset, SEEK_SET); 5427837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset = mFreeBoxOffset; 5437837c17063a4c50bc856ba59418516fdab731de7James Dong write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); 5447837c17063a4c50bc856ba59418516fdab731de7James Dong 5457837c17063a4c50bc856ba59418516fdab731de7James Dong // Free box 5462dec2b5be2056c6d9428897dc672185872d30d17James Dong fseeko(mFile, mOffset, SEEK_SET); 5477837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 5487837c17063a4c50bc856ba59418516fdab731de7James Dong write("free", 4); 5497837c17063a4c50bc856ba59418516fdab731de7James Dong 5507837c17063a4c50bc856ba59418516fdab731de7James Dong // Free temp memory 5517837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 5527837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 5537837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 5542dec2b5be2056c6d9428897dc672185872d30d17James Dong } else { 5552dec2b5be2056c6d9428897dc672185872d30d17James Dong LOGI("The mp4 file will not be streamable."); 5567837c17063a4c50bc856ba59418516fdab731de7James Dong } 5577837c17063a4c50bc856ba59418516fdab731de7James Dong 5580c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 55920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5607837c17063a4c50bc856ba59418516fdab731de7James Dong fflush(mFile); 56120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fclose(mFile); 56220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mFile = NULL; 563a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mStarted = false; 56437187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 56520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 56620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 56713aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 56813aec890216948b0c364f8f92792129d0335f506James Dong mInterleaveDurationUs = durationUs; 56913aec890216948b0c364f8f92792129d0335f506James Dong return OK; 57013aec890216948b0c364f8f92792129d0335f506James Dong} 57113aec890216948b0c364f8f92792129d0335f506James Dong 57213aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() { 57313aec890216948b0c364f8f92792129d0335f506James Dong mLock.lock(); 57413aec890216948b0c364f8f92792129d0335f506James Dong} 57513aec890216948b0c364f8f92792129d0335f506James Dong 57613aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() { 57713aec890216948b0c364f8f92792129d0335f506James Dong mLock.unlock(); 57813aec890216948b0c364f8f92792129d0335f506James Dong} 57920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 58013aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 58120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t old_offset = mOffset; 58220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 58320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 58420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1, buffer->range_length(), mFile); 58520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 58620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 58720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 58820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 58920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 59020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 59103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 59203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 59303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 59403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 59503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 59603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 59703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 59803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 59903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 60003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 60103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 60203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 60303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 60403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 60513aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 60630ab66297501757d745b9ae10da61adcd891f497Andreas Huber off_t old_offset = mOffset; 60730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 60830ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 60903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 61003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 61103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t x = length >> 24; 61203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 61303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 16) & 0xff; 61403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 61503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 8) & 0xff; 61603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 61703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = length & 0xff; 61803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 61903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 62030ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(length < 65536); 62130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 62230ab66297501757d745b9ae10da61adcd891f497Andreas Huber uint8_t x = length >> 8; 62330ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 62430ab66297501757d745b9ae10da61adcd891f497Andreas Huber x = length & 0xff; 62530ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 62603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 62730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 62830ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 62930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1, length, mFile); 63030ab66297501757d745b9ae10da61adcd891f497Andreas Huber 63103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 63203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOffset += length + 4; 63303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 63430ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset += length + 2; 63503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 63630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 63730ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 63830ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 63930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 6407837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write( 6417837c17063a4c50bc856ba59418516fdab731de7James Dong const void *ptr, size_t size, size_t nmemb, FILE *stream) { 6427837c17063a4c50bc856ba59418516fdab731de7James Dong 6437837c17063a4c50bc856ba59418516fdab731de7James Dong const size_t bytes = size * nmemb; 6447837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 6451acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 6461acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (moovBoxSize > mEstimatedMoovBoxSize) { 6477837c17063a4c50bc856ba59418516fdab731de7James Dong for (List<off_t>::iterator it = mBoxes.begin(); 6487837c17063a4c50bc856ba59418516fdab731de7James Dong it != mBoxes.end(); ++it) { 6497837c17063a4c50bc856ba59418516fdab731de7James Dong (*it) += mOffset; 6507837c17063a4c50bc856ba59418516fdab731de7James Dong } 6517837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 6527837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream); 6537837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 6547837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += (bytes + mMoovBoxBufferOffset); 6557837c17063a4c50bc856ba59418516fdab731de7James Dong free(mMoovBoxBuffer); 6567837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBuffer = NULL; 6577837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset = 0; 6587837c17063a4c50bc856ba59418516fdab731de7James Dong mWriteMoovBoxToMemory = false; 6597837c17063a4c50bc856ba59418516fdab731de7James Dong mStreamableFile = false; 6607837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6617837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 6627837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset += bytes; 6637837c17063a4c50bc856ba59418516fdab731de7James Dong } 6647837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6657837c17063a4c50bc856ba59418516fdab731de7James Dong fwrite(ptr, size, nmemb, stream); 6667837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset += bytes; 6677837c17063a4c50bc856ba59418516fdab731de7James Dong } 6687837c17063a4c50bc856ba59418516fdab731de7James Dong return bytes; 6697837c17063a4c50bc856ba59418516fdab731de7James Dong} 6707837c17063a4c50bc856ba59418516fdab731de7James Dong 67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 6720c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6747837c17063a4c50bc856ba59418516fdab731de7James Dong mBoxes.push_back(mWriteMoovBoxToMemory? 6757837c17063a4c50bc856ba59418516fdab731de7James Dong mMoovBoxBufferOffset: mOffset); 67620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 67720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 67820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 67920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 68020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 68120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 6820c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 68320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 68420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t offset = *--mBoxes.end(); 68520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 68620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6877837c17063a4c50bc856ba59418516fdab731de7James Dong if (mWriteMoovBoxToMemory) { 6887837c17063a4c50bc856ba59418516fdab731de7James Dong int32_t x = htonl(mMoovBoxBufferOffset - offset); 6897837c17063a4c50bc856ba59418516fdab731de7James Dong memcpy(mMoovBoxBuffer + offset, &x, 4); 6907837c17063a4c50bc856ba59418516fdab731de7James Dong } else { 6917837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, offset, SEEK_SET); 6927837c17063a4c50bc856ba59418516fdab731de7James Dong writeInt32(mOffset - offset); 6937837c17063a4c50bc856ba59418516fdab731de7James Dong mOffset -= 4; 6947837c17063a4c50bc856ba59418516fdab731de7James Dong fseeko(mFile, mOffset, SEEK_SET); 6957837c17063a4c50bc856ba59418516fdab731de7James Dong } 69620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 6997837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 1, mFile); 70020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 70120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 70220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 70320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 7047837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 2, mFile); 70520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 70620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 7097837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 4, mFile); 71020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 71120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 71320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 7147837c17063a4c50bc856ba59418516fdab731de7James Dong write(&x, 1, 8, mFile); 71520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 71620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 71820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 7197837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, n + 1, mFile); 72020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 72120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 72220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 7230c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 7247837c17063a4c50bc856ba59418516fdab731de7James Dong write(s, 1, 4, mFile); 72520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 72620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 72720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 7287837c17063a4c50bc856ba59418516fdab731de7James Dong write(data, 1, size, mFile); 72920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 73020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 731d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() { 732d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 733d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileSizeLimitBytes == 0) { 734d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 735d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 736d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 737956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 738d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 739d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 740d599cd4573b5a2d5914c5040e0565ef866749b77James Dong nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 741d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 742d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes); 743d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 744d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 745d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() { 746d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // No limit 747d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mMaxFileDurationLimitUs == 0) { 748d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 749d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 750d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 751d599cd4573b5a2d5914c5040e0565ef866749b77James Dong for (List<Track *>::iterator it = mTracks.begin(); 752d599cd4573b5a2d5914c5040e0565ef866749b77James Dong it != mTracks.end(); ++it) { 753d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 754d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return true; 755d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 756d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 757d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return false; 758d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 759d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 76025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 76125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 76225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 76325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 76425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 76525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 76625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 76725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 76825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 76925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 77025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 77125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 77225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 773f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 774f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("setStartTimestampUs: %lld", timeUs); 775f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong CHECK(timeUs >= 0); 7763c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 777065d1aff96818df54456053f1574aec8a234d0deJames Dong if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 778f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timeUs; 779f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong LOGI("Earliest track starting time: %lld", mStartTimestampUs); 7803c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 7813c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 7823c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 783f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() { 7843c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong Mutex::Autolock autoLock(mLock); 7853c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong return mStartTimestampUs; 7863c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong} 7873c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 78858ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() { 78958ae9c530247668f8af36e30d228c716c226b3d4James Dong Mutex::Autolock autolock(mLock); 79058ae9c530247668f8af36e30d228c716c226b3d4James Dong return mTracks.size(); 79158ae9c530247668f8af36e30d228c716c226b3d4James Dong} 79258ae9c530247668f8af36e30d228c716c226b3d4James Dong 79320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 79420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 79520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 79625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber MPEG4Writer *owner, const sp<MediaSource> &source) 79720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 79825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 79920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 80020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 801a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused(false), 802a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed(false), 803c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs(0), 804956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes(0), 805be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize(true), 80620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 80725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 808548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData(false), 80925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS(false) { 81019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber getCodecSpecificDataFromInputFormatIfPossible(); 8118f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 8121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong const char *mime; 8131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMeta->findCString(kKeyMIMEType, &mime); 8141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 8151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio = !strncasecmp(mime, "audio/", 6); 8161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 8171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 8181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 819c059860c73678a202bfa33062723e8f82fb779d9James Dong setTimeScale(); 820c059860c73678a202bfa33062723e8f82fb779d9James Dong} 821c059860c73678a202bfa33062723e8f82fb779d9James Dong 822c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() { 823c059860c73678a202bfa33062723e8f82fb779d9James Dong LOGV("setTimeScale"); 824c059860c73678a202bfa33062723e8f82fb779d9James Dong // Default time scale 825c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = 90000; 826c059860c73678a202bfa33062723e8f82fb779d9James Dong 827c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mIsAudio) { 828c059860c73678a202bfa33062723e8f82fb779d9James Dong // Use the sampling rate as the default time scale for audio track. 829c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t sampleRate; 830c059860c73678a202bfa33062723e8f82fb779d9James Dong bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 831c059860c73678a202bfa33062723e8f82fb779d9James Dong CHECK(success); 832c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = sampleRate; 833c059860c73678a202bfa33062723e8f82fb779d9James Dong } 834c059860c73678a202bfa33062723e8f82fb779d9James Dong 835c059860c73678a202bfa33062723e8f82fb779d9James Dong // If someone would like to overwrite the timescale, use user-supplied value. 836c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t timeScale; 837c059860c73678a202bfa33062723e8f82fb779d9James Dong if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 838c059860c73678a202bfa33062723e8f82fb779d9James Dong mTimeScale = timeScale; 839c059860c73678a202bfa33062723e8f82fb779d9James Dong } 840c059860c73678a202bfa33062723e8f82fb779d9James Dong 8418f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong CHECK(mTimeScale > 0); 84219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber} 84319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 84419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 84519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const char *mime; 84619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 84719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 84819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 84919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 85019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 85119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 85219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 85319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 85419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 85519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 85619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 85719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 85819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 85919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 86019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber uint32_t type; 86119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber const void *data; 86219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber size_t size; 86319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 86419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber ESDS esds(data, size); 86519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (esds.getCodecSpecificInfo(&data, &size) == OK) { 86619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificData = malloc(size); 86719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mCodecSpecificDataSize = size; 86819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber memcpy(mCodecSpecificData, data, size); 86919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber mGotAllCodecSpecificData = true; 87019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 87119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 87219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 87320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 87420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 87520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 87620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 87720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 87820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 87920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 88020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 88120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 88220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 88320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 88493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 88593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("initTrackingProgressStatus"); 88693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = -1; 88793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = false; 88893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = 0; 88993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong { 89093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t timeUs; 89193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 89293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Receive request to track progress status for every %lld us", timeUs); 89393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackEveryTimeDurationUs = timeUs; 89493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mTrackingProgressStatus = true; 89593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 89693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 89793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 89893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 8991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static 9001c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) { 9011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("ThreadWrapper: %p", me); 9021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 9031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writer->threadFunc(); 9041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return NULL; 9051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9071c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) { 9081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk: %p", chunk.mTrack); 9091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 9101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(mDone, false); 9111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 9141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunk.mTrack == it->mTrack) { // Found owner 9161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mChunks.push_back(chunk); 9171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.signal(); 9181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return; 9191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK("Received a chunk for a unknown track" == 0); 9231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9251c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeFirstChunk(ChunkInfo* info) { 9261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeFirstChunk: %p", info->mTrack); 9271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = info->mChunks.begin(); 9291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 9301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != chunkIt->mSamples.end(); ++it) { 9311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = info->mTrack->isAvc() 9331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ? addLengthPrefixedSample_l(*it) 9341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong : addSample_l(*it); 9351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it == chunkIt->mSamples.begin()) { 9361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mTrack->addChunkOffset(offset); 9371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Done with the current chunk. 9411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Release all the samples in this chunk. 9421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!chunkIt->mSamples.empty()) { 9431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin(); 9441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it)->release(); 9451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong (*it) = NULL; 9461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.erase(it); 9471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong chunkIt->mSamples.clear(); 9491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info->mChunks.erase(chunkIt); 9501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9521c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeChunks() { 9531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeChunks"); 9541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong size_t outstandingChunks = 0; 9551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mChunkInfos.empty()) { 9561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!it->mChunks.empty()) { 9581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(OK, writeOneChunk()); 9591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ++outstandingChunks; 9601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it->mTrack = NULL; 9621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.erase(it); 9631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.clear(); 9651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGD("%d chunks are written in the last batch", outstandingChunks); 9661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 9671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9681c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::writeOneChunk() { 9691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("writeOneChunk"); 9701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Find the smallest timestamp, and write that chunk out 9721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // XXX: What if some track is just too slow? 9731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 9741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Track *track = NULL; 9751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 9771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!it->mChunks.empty()) { 9781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong List<Chunk>::iterator chunkIt = it->mChunks.begin(); 9791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (chunkIt->mTimeStampUs < minTimestampUs) { 9801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong minTimestampUs = chunkIt->mTimeStampUs; 9811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong track = it->mTrack; 9821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (track == NULL) { 9871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("Nothing to be written after all"); 9881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 9891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 9911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsFirstChunk) { 9921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = false; 9931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 9951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mChunkInfos.end(); ++it) { 9961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (it->mTrack == track) { 9971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeFirstChunk(&(*it)); 9981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 9991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 10011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 10021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10031c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() { 10041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("threadFunc"); 10051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong while (!mDone) { 10071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 10081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 10091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkReadyCondition.wait(mLock); 10101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong CHECK_EQ(writeOneChunk(), OK); 10111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong { 10151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong // Write ALL samples 10161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Mutex::Autolock autolock(mLock); 10171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong writeChunks(); 10181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 10201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10211c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() { 10221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("startWriterThread"); 10231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mDone = false; 10251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsFirstChunk = true; 1026e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mDriftTimeUs = 0; 10271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong for (List<Track *>::iterator it = mTracks.begin(); 10281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong it != mTracks.end(); ++it) { 10291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong ChunkInfo info; 10301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong info.mTrack = *it; 10311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mChunkInfos.push_back(info); 10321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 10331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 10341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_t attr; 10351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_init(&attr); 10361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 10371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_create(&mThread, &attr, ThreadWrapper, this); 10381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong pthread_attr_destroy(&attr); 10391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong return OK; 10401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong} 10411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 104293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) { 1043a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (!mDone && mPaused) { 1044a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = false; 1045a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = true; 1046a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong return OK; 1047a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 104825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 104993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong int64_t startTimeUs; 105019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 105119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber startTimeUs = 0; 105219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber } 105319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber 1054e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = true; 1055e259531ce59ab1f31de5a23124b22536f6a5a767James Dong { 1056e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int32_t isNotRealTime; 1057e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) { 1058e259531ce59ab1f31de5a23124b22536f6a5a767James Dong mIsRealTimeRecording = (isNotRealTime == 0); 1059e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1060e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1061e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 106293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong initTrackingProgressStatus(params); 106393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1064f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong sp<MetaData> meta = new MetaData; 1065f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong meta->setInt64(kKeyTime, startTimeUs); 1066f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong status_t err = mSource->start(meta.get()); 106725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 106825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 106925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 107025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 107120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 107220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 107320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 107420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 107520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 107620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 1077c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = 0; 107825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 1079956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong mEstimatedTrackSizeBytes = 0; 108020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 108125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 108220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 108325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 108425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 108520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 108620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 108737187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() { 1088a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mPaused = true; 108937187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 1090a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong} 1091a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 109237187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() { 109320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 109437187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 109520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 109620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 109720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 109820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 109920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 110020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 110120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 110237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = (status_t) dummy; 110337187916a486504acaf83bea30147eb5fbf46ae5James Dong 110437187916a486504acaf83bea30147eb5fbf46ae5James Dong { 110537187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t status = mSource->stop(); 110637187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { 110737187916a486504acaf83bea30147eb5fbf46ae5James Dong err = status; 110837187916a486504acaf83bea30147eb5fbf46ae5James Dong } 110937187916a486504acaf83bea30147eb5fbf46ae5James Dong } 111037187916a486504acaf83bea30147eb5fbf46ae5James Dong 111137187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 111220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 111320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 111425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 111525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 111625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 111725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 111820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 111920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 112020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 112120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 112237187916a486504acaf83bea30147eb5fbf46ae5James Dong status_t err = track->threadEntry(); 112337187916a486504acaf83bea30147eb5fbf46ae5James Dong return (void *) err; 112420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 112520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1126548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber#include <ctype.h> 1127548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huberstatic void hexdump(const void *_data, size_t size) { 1128548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber const uint8_t *data = (const uint8_t *)_data; 1129548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t offset = 0; 1130548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber while (offset < size) { 1131548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("0x%04x ", offset); 1132548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1133548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber size_t n = size - offset; 1134548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (n > 16) { 1135548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber n = 16; 1136548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1137548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1138548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < 16; ++i) { 1139548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (i == 8) { 1140548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1141548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1142548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1143548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (offset + i < size) { 1144548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%02x ", data[offset + i]); 1145548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 1146548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1147548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1148548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1149548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1150548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf(" "); 1151548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1152548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber for (size_t i = 0; i < n; ++i) { 1153548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber if (isprint(data[offset + i])) { 1154548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("%c", data[offset + i]); 1155548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } else { 1156548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("."); 1157548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1158548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1159548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1160548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber printf("\n"); 1161548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 1162548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber offset += 16; 1163548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber } 1164548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber} 1165548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 11663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) { 11673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("getNalUnitType: %d", byte); 11683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // nal_unit_type: 5-bit unsigned integer 11703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *type = (byte & 0x1F); 11713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode( 11743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length) { 11753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("findNextStartCode: %p %d", data, length); 11773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = length; 11793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && 11803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 11813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong --bytesLeft; 11823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (bytesLeft <= 4) { 11843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft = 0; // Last parameter set 11853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 11863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return &data[length - bytesLeft]; 11873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 11883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet( 11903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 11913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseParamSet"); 11933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong CHECK(type == kNalUnitTypeSeqParamSet || 11943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong type == kNalUnitTypePicParamSet); 11953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 11963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = findNextStartCode(data, length); 11973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong *paramSetLen = nextStartCode - data; 11983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen == 0) { 11993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Param set is malformed, since its length is 0"); 12003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 12013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong AVCParamSet paramSet(*paramSetLen, data); 12043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 12053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (*paramSetLen < 4) { 12063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Seq parameter set malformed"); 12073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 12083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mSeqParamSets.empty()) { 12103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc = data[1]; 12113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible = data[2]; 12123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc = data[3]; 12133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 12143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc != data[1] || 12153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileCompatible != data[2] || 12163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mLevelIdc != data[3]) { 12173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Inconsistent profile/level found in seq parameter sets"); 12183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return NULL; 12193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mSeqParamSets.push_back(paramSet); 12223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 12233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mPicParamSets.push_back(paramSet); 12243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return nextStartCode; 12263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 12273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData( 12293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 12303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("copyAVCCodecSpecificData"); 12313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 2 bytes for each of the parameter set length field 12333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // plus the 7 bytes for the header 12343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4 + 7) { 12353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 12363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = size; 12403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificData = malloc(size); 12413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(mCodecSpecificData, data, size); 12423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 12433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 12443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData( 12463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *data, size_t size) { 12473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGV("parseAVCCodecSpecificData"); 12493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data starts with a start code. 12503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS and PPS are separated with start codes. 12513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Also, SPS must come before PPS 12523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint8_t type = kNalUnitTypeSeqParamSet; 12533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotSps = false; 12543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bool gotPps = false; 12553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *tmp = data; 12563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong const uint8_t *nextStartCode = data; 12573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t bytesLeft = size; 12583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t paramSetLen = 0; 12593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize = 0; 12603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 12613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong getNalUnitType(*(tmp + 4), &type); 12623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (type == kNalUnitTypeSeqParamSet) { 12633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (gotPps) { 12643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 12653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 12683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotSps = true; 12693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 12713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else if (type == kNalUnitTypePicParamSet) { 12723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotSps) { 12733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("SPS must come before PPS"); 12743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (!gotPps) { 12773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong gotPps = true; 12783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 12803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } else { 12813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Only SPS and PPS Nal units are expected"); 12823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nextStartCode == NULL) { 12863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 12873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Move on to find the next parameter set 12903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong bytesLeft -= nextStartCode - tmp; 12913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong tmp = nextStartCode; 12923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += (2 + paramSetLen); 12933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 12943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 12953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 12963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of seq parameter sets 12973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nSeqParamSets = mSeqParamSets.size(); 12983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets == 0) { 12993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find sequence parameter set"); 13003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 13013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nSeqParamSets > 0x1F) { 13043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many seq parameter sets (%d) found", nSeqParamSets); 13053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 13063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 13103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the number of pic parameter sets 13113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong size_t nPicParamSets = mPicParamSets.size(); 13123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets == 0) { 13133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Cound not find picture parameter set"); 13143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 13153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (nPicParamSets > 0xFF) { 13173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Too many pic parameter sets (%d) found", nPicParamSets); 13183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return ERROR_MALFORMED; 13193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong { 13233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Check on the profiles 13243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // These profiles requires additional parameter set extensions 13253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (mProfileIdc == 100 || mProfileIdc == 110 || 13263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mProfileIdc == 122 || mProfileIdc == 144) { 13273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 13283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return BAD_VALUE; 13293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return OK; 13333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong} 1334548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 133503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 133603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 1337548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber // hexdump(data, size); 1338548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 133903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 1340548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber LOGE("Already have codec specific data"); 134103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 134203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 134303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (size < 4) { 13453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong LOGE("Codec specific data length too short: %d", size); 134603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 134703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 134803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // Data is in the form of AVCCodecSpecificData 13503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (memcmp("\x00\x00\x00\x01", data, 4)) { 13513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong return copyAVCCodecSpecificData(data, size); 135203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 135303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong if (parseAVCCodecSpecificData(data, size) != OK) { 135503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 135603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 135703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // ISO 14496-15: AVC file format 13593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong mCodecSpecificDataSize += 7; // 7 more bytes in the header 136003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 136103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 13623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = 1; // version 13633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = mProfileIdc; // profile indication 13643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[2] = mProfileCompatible; // profile compatibility 13653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[3] = mLevelIdc; 136603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 136803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 136903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 3; // length size == 4 bytes 137003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 137103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 1; // length size == 2 bytes 137203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 137303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 13743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 3-bit '111' followed by 5-bit numSequenceParameterSets 13753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nSequenceParamSets = mSeqParamSets.size(); 13763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[5] = 0xe0 | nSequenceParamSets; 13773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 6; 13783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 13793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mSeqParamSets.end(); ++it) { 13803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit sequence parameter set length 13813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t seqParamSetLength = it->mLength; 13823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = seqParamSetLength >> 8; 13833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = seqParamSetLength & 0xff; 13843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // SPS NAL unit (sequence parameter length bytes) 13863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, seqParamSetLength); 13873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + seqParamSetLength); 13883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 13893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 13903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 8-bit nPictureParameterSets 13913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong int nPictureParamSets = mPicParamSets.size(); 13923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = nPictureParamSets; 13933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += 1; 13943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 13953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong it != mPicParamSets.end(); ++it) { 13963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // 16-bit picture parameter set length 13973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong uint16_t picParamSetLength = it->mLength; 13983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[0] = picParamSetLength >> 8; 13993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header[1] = picParamSetLength & 0xff; 14003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong 14013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong // PPS Nal unit (picture parameter set length bytes) 14023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong memcpy(&header[2], it->mData, picParamSetLength); 14033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong header += (2 + picParamSetLength); 14043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong } 140503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 140603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 140703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 140803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 14098644c14618d30d9e57a69df40ed939986ebf02c4James Dongstatic bool collectStatisticalData() { 14108644c14618d30d9e57a69df40ed939986ebf02c4James Dong char value[PROPERTY_VALUE_MAX]; 14118644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (property_get("media.stagefright.record-stats", value, NULL) 14128644c14618d30d9e57a69df40ed939986ebf02c4James Dong && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 14138644c14618d30d9e57a69df40ed939986ebf02c4James Dong return true; 14148644c14618d30d9e57a69df40ed939986ebf02c4James Dong } 14158644c14618d30d9e57a69df40ed939986ebf02c4James Dong return false; 14168644c14618d30d9e57a69df40ed939986ebf02c4James Dong} 14178644c14618d30d9e57a69df40ed939986ebf02c4James Dong 141837187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() { 141930ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 142013aec890216948b0c364f8f92792129d0335f506James Dong const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 142113aec890216948b0c364f8f92792129d0335f506James Dong int64_t chunkTimestampUs = 0; 142213aec890216948b0c364f8f92792129d0335f506James Dong int32_t nChunks = 0; 142313aec890216948b0c364f8f92792129d0335f506James Dong int32_t nZeroLengthFrames = 0; 14248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 14258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t lastDurationUs = 0; // Between the previous two samples in ms 1426c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currDurationTicks = 0; // Timescale based ticks 1427c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t lastDurationTicks = 0; // Timescale based ticks 14288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleCount = 1; // Sample count in the current stts table entry 1429be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong uint32_t previousSampleSize = 0; // Size of the previous sample 1430a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong int64_t previousPausedDurationUs = 0; 14311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t timestampUs; 1432e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1433d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong sp<MetaData> meta_data; 14348644c14618d30d9e57a69df40ed939986ebf02c4James Dong bool collectStats = collectStatisticalData(); 143520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1436ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples = 0; 14371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMaxWriteTimeUs = 0; 143893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong status_t err = OK; 143920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 144093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong while (!mDone && (err = mSource->read(&buffer)) == OK) { 144120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 144220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 144320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 144413aec890216948b0c364f8f92792129d0335f506James Dong ++nZeroLengthFrames; 144520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 144620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 144720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1448a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // If the codec specific data has not been received yet, delay pause. 1449a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // After the codec specific data is received, discard what we received 1450a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong // when the track is to be paused. 1451a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mPaused && !mResumed) { 1452a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer->release(); 1453a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong buffer = NULL; 1454a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong continue; 1455a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1456a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 145730ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 145830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 145903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 146003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 146103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 1462548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber CHECK(!mGotAllCodecSpecificData); 1463548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber 14641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) { 146503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 146603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 146703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 146803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 1469be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong CHECK_EQ(OK, err); 14701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } else if (mIsMPEG4) { 147103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 147203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 147303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 147403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 147503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 147603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 147730ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 147830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 147930ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 148030ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 148130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1482548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber mGotAllCodecSpecificData = true; 148330ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 1484a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1485a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1486d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // Make a deep copy of the MediaBuffer and Metadata and release 1487d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong // the original as soon as we can 1488d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1489d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1490d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->range_length()); 1491d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong copy->set_range(0, buffer->range_length()); 1492d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data = new MetaData(*buffer->meta_data().get()); 1493d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer->release(); 1494d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong buffer = NULL; 1495d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 14961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAvc) StripStartcode(copy); 1497e136c3bb38e88315bf8797a464ebf2c788296b22James Dong 14988644c14618d30d9e57a69df40ed939986ebf02c4James Dong size_t sampleSize; 14991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong sampleSize = mIsAvc 150003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 1501d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 4 150203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 1503d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong ? copy->range_length() + 2 150403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 1505d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong : copy->range_length(); 1506050b28a593350047845a45a14cc5026221ac1620James Dong 1507d599cd4573b5a2d5914c5040e0565ef866749b77James Dong // Max file size or duration handling 15088644c14618d30d9e57a69df40ed939986ebf02c4James Dong mEstimatedTrackSizeBytes += sampleSize; 1509d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileSizeLimit()) { 1510d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1511d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1512d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1513d599cd4573b5a2d5914c5040e0565ef866749b77James Dong if (mOwner->exceedsFileDurationLimit()) { 1514d599cd4573b5a2d5914c5040e0565ef866749b77James Dong mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1515d599cd4573b5a2d5914c5040e0565ef866749b77James Dong break; 1516d599cd4573b5a2d5914c5040e0565ef866749b77James Dong } 1517d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1518050b28a593350047845a45a14cc5026221ac1620James Dong 1519d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong int32_t isSync = false; 1520d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1521d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1522d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 1523d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 1524d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong//////////////////////////////////////////////////////////////////////////////// 15258644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 1526f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mStartTimestampUs = timestampUs; 1527f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong mOwner->setStartTimestampUs(mStartTimestampUs); 15283c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 152948c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 1530a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong if (mResumed) { 1531c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong previousPausedDurationUs += (timestampUs - mTrackDurationUs - lastDurationUs); 1532a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong mResumed = false; 1533a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong } 1534a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong 1535a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs -= previousPausedDurationUs; 1536e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mIsRealTimeRecording && !mIsAudio) { 1537e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // The minor adjustment on the timestamp is heuristic/experimental 1538e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // We are adjusting the timestamp to reduce the fluctuation of the duration 1539e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // of neighboring samples. This in turn helps reduce the track header size, 1540e259531ce59ab1f31de5a23124b22536f6a5a767James Dong // especially, the number of entries in the "stts" box. 1541e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1542d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong int64_t currDriftTimeUs = mOwner->getDriftTimeUs(); 1543d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong int64_t durationUs = timestampUs + currDriftTimeUs - lastTimestampUs; 1544e259531ce59ab1f31de5a23124b22536f6a5a767James Dong int64_t diffUs = (durationUs > lastDurationUs) 1545e259531ce59ab1f31de5a23124b22536f6a5a767James Dong ? durationUs - lastDurationUs 1546e259531ce59ab1f31de5a23124b22536f6a5a767James Dong : lastDurationUs - durationUs; 1547e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (diffUs <= 5000) { // XXX: Magic number 5ms 1548e259531ce59ab1f31de5a23124b22536f6a5a767James Dong timestampUs = lastTimestampUs + lastDurationUs; 1549e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } else { 1550d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong timestampUs += currDriftTimeUs; 1551e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1552e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1553e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1554e259531ce59ab1f31de5a23124b22536f6a5a767James Dong CHECK(timestampUs >= 0); 1555e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mNumSamples > 1) { 1556e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (timestampUs <= lastTimestampUs) { 15574f86a980fee1880dca61b828599fa6d76755a485James Dong LOGW("Frame arrives too late!"); 15584f86a980fee1880dca61b828599fa6d76755a485James Dong // Don't drop the late frame, since dropping a frame may cause 15594f86a980fee1880dca61b828599fa6d76755a485James Dong // problems later during playback 15604f86a980fee1880dca61b828599fa6d76755a485James Dong 15614f86a980fee1880dca61b828599fa6d76755a485James Dong // The idea here is to avoid having two or more samples with the 15624f86a980fee1880dca61b828599fa6d76755a485James Dong // same timestamp in the output file. 15634f86a980fee1880dca61b828599fa6d76755a485James Dong if (mTimeScale >= 1000000LL) { 156440e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + 1; 15654f86a980fee1880dca61b828599fa6d76755a485James Dong } else { 156640e9940fadf22daa64c1e766fa8a855c7b149c17James Dong timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale; 15674f86a980fee1880dca61b828599fa6d76755a485James Dong } 1568e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1569e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1570e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1571a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong LOGV("time stamp: %lld and previous paused duration %lld", 1572a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong timestampUs, previousPausedDurationUs); 1573c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (timestampUs > mTrackDurationUs) { 1574c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs = timestampUs; 15753b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 15763b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 15778644c14618d30d9e57a69df40ed939986ebf02c4James Dong mSampleSizes.push_back(sampleSize); 1578ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong ++mNumSamples; 1579ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples > 2) { 1580c059860c73678a202bfa33062723e8f82fb779d9James Dong // We need to use the time scale based ticks, rather than the 1581c059860c73678a202bfa33062723e8f82fb779d9James Dong // timestamp itself to determine whether we have to use a new 1582c059860c73678a202bfa33062723e8f82fb779d9James Dong // stts entry, since we may have rounding errors. 1583c059860c73678a202bfa33062723e8f82fb779d9James Dong // The calculation is intended to reduce the accumulated 1584c059860c73678a202bfa33062723e8f82fb779d9James Dong // rounding errors. 1585c059860c73678a202bfa33062723e8f82fb779d9James Dong currDurationTicks = 1586c059860c73678a202bfa33062723e8f82fb779d9James Dong ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 1587c059860c73678a202bfa33062723e8f82fb779d9James Dong (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 1588c059860c73678a202bfa33062723e8f82fb779d9James Dong 1589c059860c73678a202bfa33062723e8f82fb779d9James Dong if (currDurationTicks != lastDurationTicks) { 15908f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1591be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 1592be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong sampleCount = 1; 1593be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1594be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; 1595be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1596be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 1597be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 1598ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 1599be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSamplesHaveSameSize = false; 1600be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 16018644c14618d30d9e57a69df40ed939986ebf02c4James Dong previousSampleSize = sampleSize; 1602be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 16038644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastDurationUs = timestampUs - lastTimestampUs; 1604c059860c73678a202bfa33062723e8f82fb779d9James Dong lastDurationTicks = currDurationTicks; 16058644c14618d30d9e57a69df40ed939986ebf02c4James Dong lastTimestampUs = timestampUs; 1606e259531ce59ab1f31de5a23124b22536f6a5a767James Dong if (mIsRealTimeRecording && mIsAudio) { 1607d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong int64_t driftTimeUs = 0; 1608d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong if (meta_data->findInt64(kKeyDriftTime, &driftTimeUs)) { 1609d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mOwner->setDriftTimeUs(driftTimeUs); 1610e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 1611e259531ce59ab1f31de5a23124b22536f6a5a767James Dong } 161220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1613d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong if (isSync != 0) { 1614ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mStssTableEntries.push_back(mNumSamples); 1615d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong } 1616d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong 161793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mTrackingProgressStatus) { 161893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong if (mPreviousTrackTimeUs <= 0) { 161993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = mStartTimestampUs; 162093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 1621faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackProgressStatus(timestampUs); 162293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 162358ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 16241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong off_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 162558ae9c530247668f8af36e30d228c716c226b3d4James Dong : mOwner->addSample_l(copy); 162658ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mChunkOffsets.empty()) { 162758ae9c530247668f8af36e30d228c716c226b3d4James Dong mChunkOffsets.push_back(offset); 162858ae9c530247668f8af36e30d228c716c226b3d4James Dong } 162958ae9c530247668f8af36e30d228c716c226b3d4James Dong copy->release(); 163058ae9c530247668f8af36e30d228c716c226b3d4James Dong copy = NULL; 163158ae9c530247668f8af36e30d228c716c226b3d4James Dong continue; 163258ae9c530247668f8af36e30d228c716c226b3d4James Dong } 163313aec890216948b0c364f8f92792129d0335f506James Dong 163413aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.push_back(copy); 163513aec890216948b0c364f8f92792129d0335f506James Dong if (interleaveDurationUs == 0) { 163613aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(++nChunks, 1, 1); 163713aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 16381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 163913aec890216948b0c364f8f92792129d0335f506James Dong } else { 164013aec890216948b0c364f8f92792129d0335f506James Dong if (chunkTimestampUs == 0) { 164113aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 164213aec890216948b0c364f8f92792129d0335f506James Dong } else { 164313aec890216948b0c364f8f92792129d0335f506James Dong if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 164413aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 16458644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (collectStats) { 16468644c14618d30d9e57a69df40ed939986ebf02c4James Dong mChunkDurations.push_back(timestampUs - chunkTimestampUs); 16478644c14618d30d9e57a69df40ed939986ebf02c4James Dong } 164813aec890216948b0c364f8f92792129d0335f506James Dong if (nChunks == 1 || // First chunk 164913aec890216948b0c364f8f92792129d0335f506James Dong (--(mStscTableEntries.end()))->samplesPerChunk != 165013aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size()) { 165113aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, 165213aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.size(), 1); 165313aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 165413aec890216948b0c364f8f92792129d0335f506James Dong } 16551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 165613aec890216948b0c364f8f92792129d0335f506James Dong chunkTimestampUs = timestampUs; 165713aec890216948b0c364f8f92792129d0335f506James Dong } 165813aec890216948b0c364f8f92792129d0335f506James Dong } 165913aec890216948b0c364f8f92792129d0335f506James Dong } 166013aec890216948b0c364f8f92792129d0335f506James Dong 166120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 166225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 16638644c14618d30d9e57a69df40ed939986ebf02c4James Dong if (mSampleSizes.empty()) { 166437187916a486504acaf83bea30147eb5fbf46ae5James Dong err = ERROR_MALFORMED; 1665690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else if (OK != checkCodecSpecificData()) { 1666690f546b0ee548dbfe997df36418e5302ec2d786James Dong err = ERROR_MALFORMED; 1667f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong } 1668faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, -1, err); 1669be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong 167013aec890216948b0c364f8f92792129d0335f506James Dong // Last chunk 167158ae9c530247668f8af36e30d228c716c226b3d4James Dong if (mOwner->numTracks() == 1) { 1672ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong StscTableEntry stscEntry(1, mNumSamples, 1); 167358ae9c530247668f8af36e30d228c716c226b3d4James Dong mStscTableEntries.push_back(stscEntry); 167458ae9c530247668f8af36e30d228c716c226b3d4James Dong } else if (!mChunkSamples.empty()) { 167513aec890216948b0c364f8f92792129d0335f506James Dong ++nChunks; 167613aec890216948b0c364f8f92792129d0335f506James Dong StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1); 167713aec890216948b0c364f8f92792129d0335f506James Dong mStscTableEntries.push_back(stscEntry); 16781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong bufferChunk(timestampUs); 167913aec890216948b0c364f8f92792129d0335f506James Dong } 168013aec890216948b0c364f8f92792129d0335f506James Dong 1681be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // We don't really know how long the last frame lasts, since 1682be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // there is no frame time after it, just repeat the previous 1683be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong // frame's duration. 1684ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong if (mNumSamples == 1) { 16858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong lastDurationUs = 0; // A single sample's duration 1686be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 1687be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong ++sampleCount; // Count for the last sample 1688be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 16898f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1690be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mSttsTableEntries.push_back(sttsEntry); 1691c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong mTrackDurationUs += lastDurationUs; 169225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 16931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. Max write time: %lld us - %s", 16941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong count, nZeroLengthFrames, mNumSamples, mMaxWriteTimeUs, mIsAudio? "audio": "video"); 1695365a963142093a1cd8efdcea76b5f65096a5b115James Dong 16961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong logStatisticalData(mIsAudio); 169737187916a486504acaf83bea30147eb5fbf46ae5James Dong if (err == ERROR_END_OF_STREAM) { 169837187916a486504acaf83bea30147eb5fbf46ae5James Dong return OK; 169937187916a486504acaf83bea30147eb5fbf46ae5James Dong } 170037187916a486504acaf83bea30147eb5fbf46ae5James Dong return err; 1701365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1702365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1703faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 1704faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong LOGV("trackProgressStatus: %lld us", timeUs); 1705215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (mTrackEveryTimeDurationUs > 0 && 1706215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 170793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong LOGV("Fire time tracking progress status at %lld us", timeUs); 1708faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err); 170993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong mPreviousTrackTimeUs = timeUs; 171093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong } 171193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong} 171293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong 1713faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus( 1714faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong const MPEG4Writer::Track* track, int64_t timeUs, status_t err) { 1715faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong Mutex::Autolock lock(mLock); 1716faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t nTracks = mTracks.size(); 1717faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks >= 1); 1718faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(nTracks < 64); // Arbitrary number 1719faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1720faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong int32_t trackNum = 0; 1721faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#if 0 1722faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // In the worst case, we can put the trackNum 1723faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // along with MEDIA_RECORDER_INFO_COMPLETION_STATUS 1724faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // to report the progress. 1725faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong for (List<Track *>::iterator it = mTracks.begin(); 1726faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong it != mTracks.end(); ++it, ++trackNum) { 1727faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (track == (*it)) { 1728faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong break; 1729faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1730faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1731faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#endif 1732faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong CHECK(trackNum < nTracks); 1733faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum <<= 16; 1734faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1735faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Error notification 1736faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Do not consider ERROR_END_OF_STREAM an error 1737faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (err != OK && err != ERROR_END_OF_STREAM) { 1738faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_ERROR, 1739faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_ERROR_UNKNOWN, 1740faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 1741faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 1742faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1743faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1744faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong if (timeUs == -1) { 1745faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send completion notification 1746faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 1747faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS, 1748faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong err); 1749faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong return; 1750faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } else { 1751faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong // Send progress status 1752faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong notify(MEDIA_RECORDER_EVENT_INFO, 1753faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, 1754faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong timeUs / 1000); 1755faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong } 1756faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong} 1757faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong 1758215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dongvoid MPEG4Writer::Track::findMinAvgMaxSampleDurationMs( 1759215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t *min, int32_t *avg, int32_t *max) { 17608644c14618d30d9e57a69df40ed939986ebf02c4James Dong CHECK(!mSampleSizes.empty()); 1761c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong int32_t avgSampleDurationMs = mTrackDurationUs / 1000 / mNumSamples; 1762215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t minSampleDurationMs = 0x7FFFFFFF; 1763215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t maxSampleDurationMs = 0; 1764365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1765365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != mSttsTableEntries.end(); ++it) { 17668f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t sampleDurationMs = 17678f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000; 1768215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (sampleDurationMs > maxSampleDurationMs) { 1769215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong maxSampleDurationMs = sampleDurationMs; 1770215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong } else if (sampleDurationMs < minSampleDurationMs) { 1771215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong minSampleDurationMs = sampleDurationMs; 1772365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1773215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("sample duration: %d ms", sampleDurationMs); 1774365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1775215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(minSampleDurationMs != 0); 1776215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(avgSampleDurationMs != 0); 1777215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong CHECK(maxSampleDurationMs != 0); 1778215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *min = minSampleDurationMs; 1779215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *avg = avgSampleDurationMs; 1780215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong *max = maxSampleDurationMs; 1781365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1782365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1783365a963142093a1cd8efdcea76b5f65096a5b115James Dong// Don't count the last duration 1784365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) { 1785365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1786365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunkDuration = duration; 1787365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t maxChunkDuration = duration; 1788365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (mChunkDurations.size() > 1) { 1789365a963142093a1cd8efdcea76b5f65096a5b115James Dong for (List<int64_t>::iterator it = mChunkDurations.begin(); 1790365a963142093a1cd8efdcea76b5f65096a5b115James Dong it != --mChunkDurations.end(); ++it) { 1791365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (minChunkDuration > (*it)) { 1792365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunkDuration = (*it); 1793365a963142093a1cd8efdcea76b5f65096a5b115James Dong } else if (maxChunkDuration < (*it)) { 1794365a963142093a1cd8efdcea76b5f65096a5b115James Dong maxChunkDuration = (*it); 1795365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1796365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1797365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1798365a963142093a1cd8efdcea76b5f65096a5b115James Dong *min = minChunkDuration; 1799365a963142093a1cd8efdcea76b5f65096a5b115James Dong *max = maxChunkDuration; 1800365a963142093a1cd8efdcea76b5f65096a5b115James Dong} 1801365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1802365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::logStatisticalData(bool isAudio) { 1803c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong if (mTrackDurationUs <= 0 || mSampleSizes.empty()) { 1804365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("nothing is recorded"); 1805365a963142093a1cd8efdcea76b5f65096a5b115James Dong return; 1806365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1807365a963142093a1cd8efdcea76b5f65096a5b115James Dong 18088644c14618d30d9e57a69df40ed939986ebf02c4James Dong bool collectStats = collectStatisticalData(); 1809365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1810365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (collectStats) { 1811215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("%s track - duration %lld us, total %d frames", 1812c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong isAudio? "audio": "video", mTrackDurationUs, 1813ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mNumSamples); 1814215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong int32_t min, avg, max; 1815215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong findMinAvgMaxSampleDurationMs(&min, &avg, &max); 1816215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max); 1817215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong if (!isAudio) { 1818215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float avgFps = 1000.0 / avg; 1819215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float minFps = 1000.0 / max; 1820215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong float maxFps = 1000.0 / min; 1821365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f", 1822215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong minFps, avgFps, maxFps); 1823365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1824365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1825365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t totalBytes = 0; 18268644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 18278644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 18288644c14618d30d9e57a69df40ed939986ebf02c4James Dong totalBytes += (*it); 1829365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1830c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong float bitRate = (totalBytes * 8000000.0) / mTrackDurationUs; 1831365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("avg bit rate (bps): %.2f", bitRate); 1832365a963142093a1cd8efdcea76b5f65096a5b115James Dong 1833365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t duration = mOwner->interleaveDuration(); 1834365a963142093a1cd8efdcea76b5f65096a5b115James Dong if (duration != 0) { // If interleaving is enabled 1835365a963142093a1cd8efdcea76b5f65096a5b115James Dong int64_t minChunk, maxChunk; 1836365a963142093a1cd8efdcea76b5f65096a5b115James Dong findMinMaxChunkDurations(&minChunk, &maxChunk); 1837365a963142093a1cd8efdcea76b5f65096a5b115James Dong LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld", 1838365a963142093a1cd8efdcea76b5f65096a5b115James Dong minChunk, duration, maxChunk); 1839365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 1840365a963142093a1cd8efdcea76b5f65096a5b115James Dong } 184113aec890216948b0c364f8f92792129d0335f506James Dong} 184213aec890216948b0c364f8f92792129d0335f506James Dong 1843d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 1844d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong LOGV("setDriftTimeUs: %lld us", driftTimeUs); 1845e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 1846d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong mDriftTimeUs = driftTimeUs; 1847e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 1848e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 1849e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() { 1850e259531ce59ab1f31de5a23124b22536f6a5a767James Dong LOGV("getDriftTimeUs: %lld us", mDriftTimeUs); 1851e259531ce59ab1f31de5a23124b22536f6a5a767James Dong Mutex::Autolock autolock(mLock); 1852e259531ce59ab1f31de5a23124b22536f6a5a767James Dong return mDriftTimeUs; 1853e259531ce59ab1f31de5a23124b22536f6a5a767James Dong} 1854e259531ce59ab1f31de5a23124b22536f6a5a767James Dong 18551c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 18561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong LOGV("bufferChunk"); 18571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong 18581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t startTimeUs = systemTime() / 1000; 18591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong Chunk chunk(this, timestampUs, mChunkSamples); 18601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->bufferChunk(chunk); 186113aec890216948b0c364f8f92792129d0335f506James Dong mChunkSamples.clear(); 18621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong int64_t endTimeUs = systemTime() / 1000; 18631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mMaxWriteTimeUs < endTimeUs - startTimeUs) { 18641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mMaxWriteTimeUs = endTimeUs - startTimeUs; 18651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong } 186620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 186720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 18683b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 1869c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong return mTrackDurationUs; 187020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 187120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1872d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 1873d599cd4573b5a2d5914c5040e0565ef866749b77James Dong return mEstimatedTrackSizeBytes; 1874d599cd4573b5a2d5914c5040e0565ef866749b77James Dong} 1875d599cd4573b5a2d5914c5040e0565ef866749b77James Dong 1876690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const { 1877690f546b0ee548dbfe997df36418e5302ec2d786James Dong const char *mime; 1878690f546b0ee548dbfe997df36418e5302ec2d786James Dong CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 1879690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 1880690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 1881690f546b0ee548dbfe997df36418e5302ec2d786James Dong !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1882690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (!mCodecSpecificData || 1883690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize <= 0) { 1884690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Missing codec specific data 1885690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 1886690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 1887690f546b0ee548dbfe997df36418e5302ec2d786James Dong } else { 1888690f546b0ee548dbfe997df36418e5302ec2d786James Dong if (mCodecSpecificData || 1889690f546b0ee548dbfe997df36418e5302ec2d786James Dong mCodecSpecificDataSize > 0) { 1890690f546b0ee548dbfe997df36418e5302ec2d786James Dong // Unexepected codec specific data found 1891690f546b0ee548dbfe997df36418e5302ec2d786James Dong return ERROR_MALFORMED; 1892690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 1893690f546b0ee548dbfe997df36418e5302ec2d786James Dong } 1894690f546b0ee548dbfe997df36418e5302ec2d786James Dong return OK; 1895690f546b0ee548dbfe997df36418e5302ec2d786James Dong} 1896690f546b0ee548dbfe997df36418e5302ec2d786James Dong 18971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader( 18981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong int32_t trackID, bool use32BitOffset) { 189920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 190020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 19010c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 190220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19038f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong LOGV("%s track time scale: %d", 19041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mIsAudio? "Audio": "Video", mTimeScale); 19058f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 190620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 19078f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mvhdTimeScale = mOwner->getTimeScale(); 19088f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t trakDurationUs = getDurationUs(); 190920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 191020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 191120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 191220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 19131acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Flags = 7 to indicate that the track is enabled, and 19141acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // part of the presentation 19151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x07); // version=0, flags=7 191620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 191720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 191820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 191920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 19208f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t tkhdDuration = 19218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 19228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(tkhdDuration); // in mvhd timescale 192320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 192420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 192520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 192620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 19271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 192820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 192920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 193020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); // matrix 193120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 193220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 193320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 193420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); 193520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 193620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 193720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 193820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x40000000); 193920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 194120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 194220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 194320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 194420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 194520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 194620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 19470c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 194820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1949050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(width << 16); // 32-bit fixed-point value 1950050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(height << 16); // 32-bit fixed-point value 195120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 195220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 195320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1954f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 1955f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong if (mStartTimestampUs != moovStartTimeUs) { 19563c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("edts"); 19573c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->beginBox("elst"); 19581acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 19591acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(2); // never ends with an empty list 19608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 19618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // First elst entry: specify the starting time offset 19628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; 19638f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; 19648f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timecale 19658f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(-1); // starting time offset 19668f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(1 << 16); // rate = 1.0 19678f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong 19688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong // Second elst entry: specify the track duration 19698f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 19708f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(seg); // in mvhd timescale 19711acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0); 19721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); 19733c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 19743c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong mOwner->endBox(); 19753c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong } 19763c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong 197720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 197820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 197920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 198020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 198120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 198220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 19838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mTimeScale); // media timescale 19848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 19858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(mdhdDuration); // use media timescale 19861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Language follows the three letter standard ISO-639-2/T 19871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // 'e', 'n', 'g' for "English", for instance. 19881acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Each character is packed as the difference between its ASCII value and 0x60. 19891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // For "English", these are 00101, 01110, 00111. 19901acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // XXX: Where is the padding bit located: 0x15C7? 19911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(0); // language code 199220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 199320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 199420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 199520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 199620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 1997050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // component type: should be mhlr 19981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 199920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 200020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 200120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 20021acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // Removing "r" for the name string just makes the string 4 byte aligned 20031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 200420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 200520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 200620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 20071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 200820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 200920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 201020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 201120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 201220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 201320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 201420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 20151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(0x01); // version=0, flags=1 201620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 201720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 201820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 201920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 202020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 202120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 2022050b28a593350047845a45a14cc5026221ac1620James Dong 2023050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dinf"); 2024050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("dref"); 2025050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 20261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // entry count (either url or urn) 20271acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // The table index here refers to the sample description index 20281acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // in the sample table entries. 2029050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("url "); 20301acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2031050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // url 2032050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dref 2033050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // dinf 2034050b28a593350047845a45a14cc5026221ac1620James Dong 203520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 203620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 203720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 203820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 203920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 20401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (mIsAudio) { 204125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 204218291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 204325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 204418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 204525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 2046050b28a593350047845a45a14cc5026221ac1620James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2047050b28a593350047845a45a14cc5026221ac1620James Dong fourcc = "mp4a"; 204825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 204925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 205025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 205125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 205225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 205325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 205420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 205520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 2056050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x1); // data ref index 205720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 205820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 2059050b28a593350047845a45a14cc5026221ac1620James Dong int32_t nChannels; 2060050b28a593350047845a45a14cc5026221ac1620James Dong CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2061050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(nChannels); // channel count 206220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 206320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 206420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 206520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 206620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 206720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 20680c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 206920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 2070050b28a593350047845a45a14cc5026221ac1620James Dong if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2071050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("esds"); 207251dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 207351dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 2074050b28a593350047845a45a14cc5026221ac1620James Dong 2075050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2076050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x03); // ES_DescrTag 2077050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(23 + mCodecSpecificDataSize); 2078050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x0000);// ES_ID 2079050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); 2080050b28a593350047845a45a14cc5026221ac1620James Dong 2081050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2082050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(15 + mCodecSpecificDataSize); 2083050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2084050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x15); // streamType AudioStream 2085050b28a593350047845a45a14cc5026221ac1620James Dong 2086050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt16(0x03); // XXX 2087050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x00); // buffer size 24-bit 2088050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // max bit rate 2089050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(96000); // avg bit rate 2090050b28a593350047845a45a14cc5026221ac1620James Dong 2091050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2092050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt8(mCodecSpecificDataSize); 2093050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2094050b28a593350047845a45a14cc5026221ac1620James Dong 2095050b28a593350047845a45a14cc5026221ac1620James Dong static const uint8_t kData2[] = { 2096050b28a593350047845a45a14cc5026221ac1620James Dong 0x06, // SLConfigDescriptorTag 2097050b28a593350047845a45a14cc5026221ac1620James Dong 0x01, 2098050b28a593350047845a45a14cc5026221ac1620James Dong 0x02 2099050b28a593350047845a45a14cc5026221ac1620James Dong }; 2100050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->write(kData2, sizeof(kData2)); 2101050b28a593350047845a45a14cc5026221ac1620James Dong 2102050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // esds 21035aff464f67322cd13dc8ed165806971cfff2e4d5James Dong } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 21045aff464f67322cd13dc8ed165806971cfff2e4d5James Dong !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 21055aff464f67322cd13dc8ed165806971cfff2e4d5James Dong // 3gpp2 Spec AMRSampleEntry fields 21065aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->beginBox("damr"); 21075aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeCString(" "); // vendor: 4 bytes 21085aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // decoder version 21095aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt16(0x83FF); // mode set: all enabled 21105aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(0); // mode change period 21115aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->writeInt8(1); // frames per sample 21125aff464f67322cd13dc8ed165806971cfff2e4d5James Dong mOwner->endBox(); 2113050b28a593350047845a45a14cc5026221ac1620James Dong } 211420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 211520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 211618291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 211720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 211818291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 211920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 212030ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 212130ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 212220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 212325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 21240c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 212520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 212620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 212720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 212820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 21291acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt16(1); // data ref index 213020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 213120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 213220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 213320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 213420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 213520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 213620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 213720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 213820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 21390c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 214020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 214120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 214220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 214320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 214420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 214520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 214620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 214720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 214820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 214920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 215020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21510c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 215220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 215318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2154a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificData); 2155a37923e9a57d489e7bed2129369219039fa5f12cJames Dong CHECK(mCodecSpecificDataSize > 0); 215620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 215720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 215820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 215920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 216020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 216120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 216220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 216320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 216420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 216520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 216620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 216720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 216820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 216920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 217020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 217120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 217220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 217320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 217420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 217520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 2176050b28a593350047845a45a14cc5026221ac1620James Dong 217720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 217820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 217920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 218020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 218120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 218220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 218320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 218420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 218520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 218620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 218720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 218820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 218920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 219018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 219120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 219220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 219320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 219420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 219520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 219620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 219720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 219820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 219930ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 220051dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificData); 220151dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong CHECK(mCodecSpecificDataSize > 0); 220230ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 220330ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 220430ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 220520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 220630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 22071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox("pasp"); 22081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong // This is useful if the pixel is not square 22091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // hspacing 22101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(1 << 16); // vspacing 22111acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // pasp 221230ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 221320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 221420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 221520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 221620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 221720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2218be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(mSttsTableEntries.size()); 2219c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t prevTimestampUs = 0; 2220be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 2221be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong it != mSttsTableEntries.end(); ++it) { 2222be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(it->sampleCount); 2223c059860c73678a202bfa33062723e8f82fb779d9James Dong 2224c059860c73678a202bfa33062723e8f82fb779d9James Dong // Make sure that we are calculating the sample duration the exactly 2225c059860c73678a202bfa33062723e8f82fb779d9James Dong // same way as we made decision on how to create stts entries. 2226c059860c73678a202bfa33062723e8f82fb779d9James Dong int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs; 2227c059860c73678a202bfa33062723e8f82fb779d9James Dong int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL - 2228c059860c73678a202bfa33062723e8f82fb779d9James Dong (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2229c059860c73678a202bfa33062723e8f82fb779d9James Dong prevTimestampUs += (it->sampleCount * it->sampleDurationUs); 2230c059860c73678a202bfa33062723e8f82fb779d9James Dong 22318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->writeInt32(dur); 223220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 223320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 223420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong if (!mIsAudio) { 2236050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->beginBox("stss"); 2237050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(0); // version=0, flags=0 2238050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames 2239050b28a593350047845a45a14cc5026221ac1620James Dong for (List<int32_t>::iterator it = mStssTableEntries.begin(); 2240050b28a593350047845a45a14cc5026221ac1620James Dong it != mStssTableEntries.end(); ++it) { 2241050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->writeInt32(*it); 2242050b28a593350047845a45a14cc5026221ac1620James Dong } 2243050b28a593350047845a45a14cc5026221ac1620James Dong mOwner->endBox(); // stss 2244050b28a593350047845a45a14cc5026221ac1620James Dong } 2245050b28a593350047845a45a14cc5026221ac1620James Dong 224620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 224720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 2248be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (mSamplesHaveSameSize) { 22498644c14618d30d9e57a69df40ed939986ebf02c4James Dong List<size_t>::iterator it = mSampleSizes.begin(); 22508644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); // default sample size 2251be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } else { 2252be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong mOwner->writeInt32(0); 2253be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 2254ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong mOwner->writeInt32(mNumSamples); 2255be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong if (!mSamplesHaveSameSize) { 22568644c14618d30d9e57a69df40ed939986ebf02c4James Dong for (List<size_t>::iterator it = mSampleSizes.begin(); 22578644c14618d30d9e57a69df40ed939986ebf02c4James Dong it != mSampleSizes.end(); ++it) { 22588644c14618d30d9e57a69df40ed939986ebf02c4James Dong mOwner->writeInt32(*it); 2259be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong } 226020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 226120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 226220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 226320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 226420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 226513aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mStscTableEntries.size()); 226613aec890216948b0c364f8f92792129d0335f506James Dong for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 226713aec890216948b0c364f8f92792129d0335f506James Dong it != mStscTableEntries.end(); ++it) { 226813aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->firstChunk); 226913aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->samplesPerChunk); 227013aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(it->sampleDescriptionId); 227120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 227220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 22731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->beginBox(use32BitOffset? "stco": "co64"); 227420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 227513aec890216948b0c364f8f92792129d0335f506James Dong mOwner->writeInt32(mChunkOffsets.size()); 227613aec890216948b0c364f8f92792129d0335f506James Dong for (List<off_t>::iterator it = mChunkOffsets.begin(); 227713aec890216948b0c364f8f92792129d0335f506James Dong it != mChunkOffsets.end(); ++it) { 22781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong if (use32BitOffset) { 22791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt32(static_cast<int32_t>(*it)); 22801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } else { 22811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->writeInt64((*it)); 22821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong } 228320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 22848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong mOwner->endBox(); // stco or co64 228520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 228620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 22871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong mOwner->endBox(); // minf 228820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 228920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 229020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 229120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 229220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 2293