MPEG4Writer.cpp revision 03b268eac37ca2589bfff0bf58daf79d29cc14f4
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 1720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h> 1820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <ctype.h> 2020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h> 2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h> 2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h> 2420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h> 250c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h> 2618291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h> 2703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h> 2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h> 2920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h> 3020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android { 3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track { 3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic: 3525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track(MPEG4Writer *owner, const sp<MediaSource> &source); 3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ~Track(); 3720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 3825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber status_t start(); 3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void stop(); 4025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool reachedEOS(); 4120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 423b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t getDurationUs() const; 4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void writeTrackHeader(int32_t trackID); 4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate: 4620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MPEG4Writer *mOwner; 4720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> mMeta; 48693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber sp<MediaSource> mSource; 4920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber volatile bool mDone; 503b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t mMaxTimeStampUs; 5120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_t mThread; 5320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber struct SampleInfo { 5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t size; 5620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t offset; 5720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int64_t timestamp; 5820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 5920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber List<SampleInfo> mSampleInfos; 6020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *mCodecSpecificData; 6220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t mCodecSpecificDataSize; 6320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool mReachedEOS; 6525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 6620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static void *ThreadWrapper(void *me); 6720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void threadEntry(); 6820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t makeAVCCodecSpecificData( 7003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size); 7103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 7220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track(const Track &); 7320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track &operator=(const Track &); 7420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}; 7520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 7603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#define USE_NALLEN_FOUR 1 7703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 7820111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename) 7920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mFile(fopen(filename, "wb")), 8020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset(0), 8120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mMdatOffset(0) { 820c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mFile != NULL); 8320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 8420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8530ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd) 8630ab66297501757d745b9ae10da61adcd891f497Andreas Huber : mFile(fdopen(fd, "wb")), 8730ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset(0), 8830ab66297501757d745b9ae10da61adcd891f497Andreas Huber mMdatOffset(0) { 8930ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(mFile != NULL); 9030ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 9130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 9220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() { 9320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 9420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 9520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 9620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 9720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber delete *it; 9820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.clear(); 10020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 10120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1022dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 10325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber Track *track = new Track(this, source); 10420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mTracks.push_back(track); 1052dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber 1062dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber return OK; 10720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 10820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 10925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberstatus_t MPEG4Writer::start() { 11020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 11125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return UNKNOWN_ERROR; 11220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 11320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 11420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("ftyp"); 11520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 11620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 11720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc("isom"); 11820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); 11920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 12020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mMdatOffset = mOffset; 12120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber write("\x00\x00\x00\x01mdat????????", 16); 12220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 12320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 12420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 12525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber status_t err = (*it)->start(); 12625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 12725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 12825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it2 = mTracks.begin(); 12925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it2 != it; ++it2) { 13025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber (*it2)->stop(); 13125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 13225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 13325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 13425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 13520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 13625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 13725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 13820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 13920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 14020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::stop() { 14120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mFile == NULL) { 14220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return; 14320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 14420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 14520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int64_t max_duration = 0; 14620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 14720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it) { 14820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber (*it)->stop(); 14920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1503b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber int64_t duration = (*it)->getDurationUs(); 15120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (duration > max_duration) { 15220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber max_duration = duration; 15320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 15420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 15520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber // Fix up the size of the 'mdat' chunk. 15720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fseek(mFile, mMdatOffset + 8, SEEK_SET); 15820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int64_t size = mOffset - mMdatOffset; 15920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size = hton64(size); 16020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(&size, 1, 8, mFile); 16120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fseek(mFile, mOffset, SEEK_SET); 16220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 16320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 16420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 16520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("moov"); 16620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 16720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber beginBox("mvhd"); 16820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // version=0, flags=0 16920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // creation time 17020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(now); // modification time 17120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(1000); // timescale 1723b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber writeInt32(max_duration / 1000); 17320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); // rate 17420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0x100); // volume 17520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt16(0); // reserved 17620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 17720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // reserved 17820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); // matrix 17920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 18020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 18120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 18220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x10000); 18320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 18520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 18620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0x40000000); 18720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 18820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 18920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 19020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 19120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 19220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); // predefined 19320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mTracks.size() + 1); // nextTrackID 19420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // mvhd 19520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 19620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t id = 1; 19720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 19820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mTracks.end(); ++it, ++id) { 19920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber (*it)->writeTrackHeader(id); 20020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 20120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber endBox(); // moov 20220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 2030c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(mBoxes.empty()); 20420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 20520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fclose(mFile); 20620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mFile = NULL; 20720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 20820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 20920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberoff_t MPEG4Writer::addSample(MediaBuffer *buffer) { 21020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Mutex::Autolock autoLock(mLock); 21120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t old_offset = mOffset; 21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 21520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 1, buffer->range_length(), mFile); 21620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += buffer->range_length(); 21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return old_offset; 22020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 22120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 22203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) { 22303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->range_length() < 4) { 22403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return; 22503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 22603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 22703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *ptr = 22803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 22903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 23003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 23103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->set_range( 23203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_offset() + 4, buffer->range_length() - 4); 23303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 23403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 23503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 23630ab66297501757d745b9ae10da61adcd891f497Andreas Huberoff_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) { 23730ab66297501757d745b9ae10da61adcd891f497Andreas Huber Mutex::Autolock autoLock(mLock); 23830ab66297501757d745b9ae10da61adcd891f497Andreas Huber 23903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber StripStartcode(buffer); 24003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 24130ab66297501757d745b9ae10da61adcd891f497Andreas Huber off_t old_offset = mOffset; 24230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 24330ab66297501757d745b9ae10da61adcd891f497Andreas Huber size_t length = buffer->range_length(); 24403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 24503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 24603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t x = length >> 24; 24703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 24803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 16) & 0xff; 24903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 25003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = (length >> 8) & 0xff; 25103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 25203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber x = length & 0xff; 25303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber fwrite(&x, 1, 1, mFile); 25403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 25530ab66297501757d745b9ae10da61adcd891f497Andreas Huber CHECK(length < 65536); 25630ab66297501757d745b9ae10da61adcd891f497Andreas Huber 25730ab66297501757d745b9ae10da61adcd891f497Andreas Huber uint8_t x = length >> 8; 25830ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 25930ab66297501757d745b9ae10da61adcd891f497Andreas Huber x = length & 0xff; 26030ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite(&x, 1, 1, mFile); 26103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 26230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 26330ab66297501757d745b9ae10da61adcd891f497Andreas Huber fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 26430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 1, length, mFile); 26530ab66297501757d745b9ae10da61adcd891f497Andreas Huber 26603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 26703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOffset += length + 4; 26803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 26930ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOffset += length + 2; 27003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 27130ab66297501757d745b9ae10da61adcd891f497Andreas Huber 27230ab66297501757d745b9ae10da61adcd891f497Andreas Huber return old_offset; 27330ab66297501757d745b9ae10da61adcd891f497Andreas Huber} 27430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 27520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) { 2760c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(fourcc), 4); 27720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 27820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.push_back(mOffset); 27920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 28020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(0); 28120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeFourcc(fourcc); 28220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 28320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 28420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() { 2850c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!mBoxes.empty()); 28620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 28720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber off_t offset = *--mBoxes.end(); 28820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mBoxes.erase(--mBoxes.end()); 28920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 29020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fseek(mFile, offset, SEEK_SET); 29120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber writeInt32(mOffset - offset); 29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset -= 4; 29320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fseek(mFile, mOffset, SEEK_SET); 29420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 29520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 29620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) { 29720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(&x, 1, 1, mFile); 29820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ++mOffset; 29920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 30020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 30120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) { 30220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htons(x); 30320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(&x, 1, 2, mFile); 30420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += 2; 30520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 30620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 30720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) { 30820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = htonl(x); 30920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(&x, 1, 4, mFile); 31020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += 4; 31120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 31220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 31320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) { 31420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber x = hton64(x); 31520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(&x, 1, 8, mFile); 31620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += 8; 31720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 31820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 31920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) { 32020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t n = strlen(s); 32120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 32220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(s, 1, n + 1, mFile); 32320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += n + 1; 32420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 32520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 32620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) { 3270c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK_EQ(strlen(s), 4); 32820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(s, 1, 4, mFile); 32920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += 4; 33020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 33120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 33220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) { 33320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber fwrite(data, 1, size, mFile); 33420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOffset += size; 33520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 33620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 33725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() { 33825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber bool allDone = true; 33925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber for (List<Track *>::iterator it = mTracks.begin(); 34025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber it != mTracks.end(); ++it) { 34125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (!(*it)->reachedEOS()) { 34225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber allDone = false; 34325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber break; 34425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 34525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 34625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 34725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return allDone; 34825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 34925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 35020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber//////////////////////////////////////////////////////////////////////////////// 35120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 35220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track( 35325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber MPEG4Writer *owner, const sp<MediaSource> &source) 35420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber : mOwner(owner), 35525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mMeta(source->getFormat()), 35620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource(source), 35720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone(false), 3583b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mMaxTimeStampUs(0), 35920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData(NULL), 36025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mCodecSpecificDataSize(0), 36125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS(false) { 36220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 36320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 36420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() { 36520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber stop(); 36620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 36720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mCodecSpecificData != NULL) { 36820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber free(mCodecSpecificData); 36920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = NULL; 37020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 37120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 37220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 37325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberstatus_t MPEG4Writer::Track::start() { 37425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber status_t err = mSource->start(); 37525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 37625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber if (err != OK) { 37725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mDone = mReachedEOS = true; 37825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return err; 37925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 38020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 38120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_t attr; 38220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_init(&attr); 38320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 38420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 38520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = false; 3863b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mMaxTimeStampUs = 0; 38725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = false; 38820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 38925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber pthread_create(&mThread, &attr, ThreadWrapper, this); 39020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_attr_destroy(&attr); 39125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 39225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return OK; 39320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 39420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 39520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::stop() { 39620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (mDone) { 39720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return; 39820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 39920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 40020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mDone = true; 40120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 40220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber void *dummy; 40320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber pthread_join(mThread, &dummy); 40420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 40520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSource->stop(); 40620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 40720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 40825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() { 40925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber return mReachedEOS; 41025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber} 41125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 41220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static 41320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) { 41420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber Track *track = static_cast<Track *>(me); 41520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 41620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber track->threadEntry(); 41720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 41820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber return NULL; 41920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 42020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 42103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData( 42203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data, size_t size) { 42303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 42403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 42503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 42603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 42703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { 42803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // Must start with a start-code. 42903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 43003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 43103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 43203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t picParamOffset = 4; 43303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber while (picParamOffset + 3 < size 43403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) { 43503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber ++picParamOffset; 43603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 43703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 43803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (picParamOffset + 3 >= size) { 43903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // Could not find start-code for pictureParameterSet. 44003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return ERROR_MALFORMED; 44103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 44203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 44303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t seqParamSetLength = picParamOffset - 4; 44403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t picParamSetLength = size - picParamOffset - 4; 44503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 44603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = 44703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2; 44803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 44903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 45003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber uint8_t *header = (uint8_t *)mCodecSpecificData; 45103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[0] = 1; 45203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[1] = 0x42; // profile 45303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[2] = 0x80; 45403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[3] = 0x1e; // level 45503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 45603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 45703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 3; // length size == 4 bytes 45803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 45903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[4] = 0xfc | 1; // length size == 2 bytes 46003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 46103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 46203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[5] = 0xe0 | 1; 46303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[6] = seqParamSetLength >> 8; 46403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[7] = seqParamSetLength & 0xff; 46503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(&header[8], &data[4], seqParamSetLength); 46603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header += 8 + seqParamSetLength; 46703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[0] = 1; 46803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[1] = picParamSetLength >> 8; 46903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber header[2] = picParamSetLength & 0xff; 47003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength); 47103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 47203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber return OK; 47303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber} 47403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 47520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::threadEntry() { 47620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber sp<MetaData> meta = mSource->getFormat(); 47720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 47820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber meta->findCString(kKeyMIMEType, &mime); 47930ab66297501757d745b9ae10da61adcd891f497Andreas Huber bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4); 48030ab66297501757d745b9ae10da61adcd891f497Andreas Huber bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 48130ab66297501757d745b9ae10da61adcd891f497Andreas Huber int32_t count = 0; 48220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 48320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber MediaBuffer *buffer; 48420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber while (!mDone && mSource->read(&buffer) == OK) { 48520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (buffer->range_length() == 0) { 48620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 48720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 48820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 48920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber continue; 49020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 49120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 49230ab66297501757d745b9ae10da61adcd891f497Andreas Huber ++count; 49330ab66297501757d745b9ae10da61adcd891f497Andreas Huber 49403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int32_t isCodecConfig; 49503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 49603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber && isCodecConfig) { 49703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (is_avc) { 49803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 49903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 50003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 50103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 50203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 50303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (err != OK) { 50403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber LOGE("failed to parse avc codec specific data."); 50530ab66297501757d745b9ae10da61adcd891f497Andreas Huber break; 50630ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 50703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } else if (is_mpeg4) { 50803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (mCodecSpecificData != NULL) { 50930ab66297501757d745b9ae10da61adcd891f497Andreas Huber break; 51030ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 51103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 51203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = buffer->range_length(); 51303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = malloc(mCodecSpecificDataSize); 51403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy(mCodecSpecificData, 51503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() 51603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber + buffer->range_offset(), 51703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->range_length()); 51830ab66297501757d745b9ae10da61adcd891f497Andreas Huber } 51930ab66297501757d745b9ae10da61adcd891f497Andreas Huber 52030ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer->release(); 52130ab66297501757d745b9ae10da61adcd891f497Andreas Huber buffer = NULL; 52230ab66297501757d745b9ae10da61adcd891f497Andreas Huber 52330ab66297501757d745b9ae10da61adcd891f497Andreas Huber continue; 52403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } else if (count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { 52503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // The TI mpeg4 encoder does not properly set the 52603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // codec-specific-data flag. 52730ab66297501757d745b9ae10da61adcd891f497Andreas Huber 52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const uint8_t *data = 52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 53020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const size_t size = buffer->range_length(); 53220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 53320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber size_t offset = 0; 53420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber while (offset + 3 < size) { 53520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (data[offset] == 0x00 && data[offset + 1] == 0x00 53620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) { 53720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber break; 53820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 53920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 54020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ++offset; 54120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 54220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 5430c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber // CHECK(offset + 3 < size); 544bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber if (offset + 3 >= size) { 545bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber // XXX assume the entire first chunk of data is the codec specific 546bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber // data. 547bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber offset = size; 548bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber } 54920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificDataSize = offset; 55120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mCodecSpecificData = malloc(offset); 55220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber memcpy(mCodecSpecificData, data, offset); 55320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 55420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->set_range(buffer->range_offset() + offset, size - offset); 55503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 55603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (size == offset) { 55703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->release(); 55803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer = NULL; 55903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 56003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber continue; 56103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 56203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } else if (is_avc && count < 3) { 56303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // The TI video encoder does not flag codec specific data 56403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // as such and also splits up SPS and PPS across two buffers. 56503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 56603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber const uint8_t *data = 56703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 56803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 56903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t size = buffer->range_length(); 57003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 57103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber CHECK(count == 2 || mCodecSpecificData == NULL); 57203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 57303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size_t offset = mCodecSpecificDataSize; 57403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize += size + 4; 57503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = 57603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber realloc(mCodecSpecificData, mCodecSpecificDataSize); 57703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 57803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy((uint8_t *)mCodecSpecificData + offset, 57903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber "\x00\x00\x00\x01", 4); 58003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 58103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size); 58203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 58303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer->release(); 58403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber buffer = NULL; 58503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 58603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (count == 2) { 58703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber void *tmp = mCodecSpecificData; 58803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber size = mCodecSpecificDataSize; 58903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificData = NULL; 59003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mCodecSpecificDataSize = 0; 59103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 59203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber status_t err = makeAVCCodecSpecificData( 59303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber (const uint8_t *)tmp, size); 59403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 59503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber free(tmp); 59603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber tmp = NULL; 59703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 59803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber if (err != OK) { 59903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber LOGE("failed to parse avc codec specific data."); 60003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber break; 60103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 60203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber } 60303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 60403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber continue; 60520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 60620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 60730ab66297501757d745b9ae10da61adcd891f497Andreas Huber off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer) 60830ab66297501757d745b9ae10da61adcd891f497Andreas Huber : mOwner->addSample(buffer); 60920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 61020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber SampleInfo info; 61103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber info.size = is_avc 61203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR 61303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber ? buffer->range_length() + 4 61403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else 61503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber ? buffer->range_length() + 2 61603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif 61703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber : buffer->range_length(); 61803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 61920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber info.offset = offset; 62020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 62148c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber int64_t timestampUs; 62248c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs)); 62348c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber 6243b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber if (timestampUs > mMaxTimeStampUs) { 6253b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mMaxTimeStampUs = timestampUs; 6263b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber } 6273b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber 62848c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber // Our timestamp is in ms. 62948c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber info.timestamp = (timestampUs + 500) / 1000; 63020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 63120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSampleInfos.push_back(info); 63220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 63320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer->release(); 63420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber buffer = NULL; 63520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 63625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 63725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mReachedEOS = true; 63820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 63920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 6403b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const { 6413b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber return mMaxTimeStampUs; 64220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { 64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber const char *mime; 64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findCString(kKeyMIMEType, &mime); 6470c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 64820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool is_audio = !strncasecmp(mime, "audio/", 6); 65020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber time_t now = time(NULL); 65220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("trak"); 65420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 65520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("tkhd"); 65620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 65720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 65820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(trackID); 66020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 6613b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mOwner->writeInt32(getDurationUs() / 1000); 66220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 66320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 66420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // layer 66520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // alternate group 66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(is_audio ? 0x100 : 0); // volume 66720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 66920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); // matrix 67020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 67220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x10000); 67420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 67520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 67620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 67720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x40000000); 67820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 67920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (is_audio) { 68020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 68120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); 68220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 68320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 68420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 68520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 6860c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 68720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 68820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(width); 68920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(height); 69020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 69120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // tkhd 69220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdia"); 69420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 69520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mdhd"); 69620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // creation time 69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(now); // modification time 69920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1000); // timescale 7003b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber mOwner->writeInt32(getDurationUs() / 1000); 70120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // language code XXX 70220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 70320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 70420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 70520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("hdlr"); 70620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeFourcc(is_audio ? "soun" : "vide"); 70920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 71020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 71120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 71220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeCString(""); // name 71320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 71420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("minf"); 71620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 71720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("dinf"); 71820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("dref"); 71920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 72020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); 72120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("url "); 72220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // version=0, flags=1 72320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // url 72420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // dref 72520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // dinf 72620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 72720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (is_audio) { 72820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("smhd"); 72920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 73020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // balance 73120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 73220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 73320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 73420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("vmhd"); 73520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x00000001); // version=0, flags=1 73620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // graphics mode 73720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // opcolor 73820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 73920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); 74020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 74120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 74220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // minf 74320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 74420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stbl"); 74520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 74620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsd"); 74720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 74820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); // entry count 74920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber if (is_audio) { 75025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber const char *fourcc = NULL; 75118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 75225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "samr"; 75318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 75425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber fourcc = "sawb"; 75525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } else { 75625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 75725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber CHECK(!"should not be here, unknown mime type."); 75825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber } 75925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber 76025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber mOwner->beginBox(fourcc); // audio format 76120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 76220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 76320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // data ref index 76420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 76520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 76620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(2); // channel count 76720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(16); // sample size 76820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 76920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 77020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 77120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t samplerate; 77220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 7730c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 77420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 77520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(samplerate << 16); 77620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); 77720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 77818291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 77920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("mp4v"); 78018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 78120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("s263"); 78230ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 78330ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avc1"); 78420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } else { 78525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber LOGE("Unknown mime type '%s'.", mime); 7860c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(!"should not be here, unknown mime type."); 78720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 78820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 78920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 79020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 79120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // data ref index 79220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // predefined 79320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0); // reserved 79420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 79520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 79620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // predefined 79720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 79820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t width, height; 79920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber bool success = mMeta->findInt32(kKeyWidth, &width); 80020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber success = success && mMeta->findInt32(kKeyHeight, &height); 8010c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(success); 80220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 80320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(width); 80420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(height); 80520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // horiz resolution 80620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0x480000); // vert resolution 80720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // reserved 80820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(1); // frame count 80920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(" ", 32); 81020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x18); // depth 81120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(-1); // predefined 81220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 8130c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber CHECK(23 + mCodecSpecificDataSize < 128); 81420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 81518291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 81620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("esds"); 81720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 81820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 81920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x03); // ES_DescrTag 82120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(23 + mCodecSpecificDataSize); 82220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt16(0x0000); // ES_ID 82320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x1f); 82420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 82520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x04); // DecoderConfigDescrTag 82620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(15 + mCodecSpecificDataSize); 82720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 82820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x11); // streamType VisualStream 82920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData[] = { 83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 0x77, 0x00, 83220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00, 83320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x00, 0x03, 0xe8, 0x00 83420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData, sizeof(kData)); 83620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 83820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 83920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(mCodecSpecificDataSize); 84020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 84120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber static const uint8_t kData2[] = { 84320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x06, // SLConfigDescriptorTag 84420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x01, 84520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 0x02 84620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber }; 84720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->write(kData2, sizeof(kData2)); 84820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 84920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // esds 85018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("d263"); 85220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // vendor 85420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // decoder version 85520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(10); // level: 10 85620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt8(0); // profile: 0 85720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 85820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // d263 85930ab66297501757d745b9ae10da61adcd891f497Andreas Huber } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 86030ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->beginBox("avcC"); 86130ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 86230ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // avcC 86320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 86430ab66297501757d745b9ae10da61adcd891f497Andreas Huber 86530ab66297501757d745b9ae10da61adcd891f497Andreas Huber mOwner->endBox(); // mp4v, s263 or avc1 86620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 86720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsd 86820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 86920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stts"); 87020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 87103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOwner->writeInt32(mSampleInfos.size()); 87220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 87320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber List<SampleInfo>::iterator it = mSampleInfos.begin(); 87420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int64_t last = (*it).timestamp; 87503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber int64_t lastDuration = 1; 87603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 87720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ++it; 87820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber while (it != mSampleInfos.end()) { 87920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); 88003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber lastDuration = (*it).timestamp - last; 88103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOwner->writeInt32(lastDuration); 88220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 88320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber last = (*it).timestamp; 88420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 88520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber ++it; 88620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 88703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 88803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // We don't really know how long the last frame lasts, since 88903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // there is no frame time after it, just repeat the previous 89003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber // frame's duration. 89103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOwner->writeInt32(1); 89203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber mOwner->writeInt32(lastDuration); 89303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber 89420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stts 89520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 89620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsz"); 89720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 89820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // default sample size 89920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(mSampleInfos.size()); 90020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 90120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mSampleInfos.end(); ++it) { 90220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32((*it).size); 90320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 90420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsz 90520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 90620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("stsc"); 90720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 90820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(mSampleInfos.size()); 90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber int32_t n = 1; 91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 91120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mSampleInfos.end(); ++it, ++n) { 91220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(n); 91320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); 91420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(1); 91520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 91620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stsc 91720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 91820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->beginBox("co64"); 91920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(0); // version=0, flags=0 92020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt32(mSampleInfos.size()); 92120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 92220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber it != mSampleInfos.end(); ++it, ++n) { 92320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->writeInt64((*it).offset); 92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber } 92520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // co64 92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // stbl 92820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // mdia 92920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mOwner->endBox(); // trak 93020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} 93120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 93220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber} // namespace android 933