Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2009 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef MPEG4_WRITER_H_ |
| 18 | |
| 19 | #define MPEG4_WRITER_H_ |
| 20 | |
| 21 | #include <stdio.h> |
| 22 | |
Andreas Huber | 996dddf | 2010-01-25 15:30:31 -0800 | [diff] [blame] | 23 | #include <media/stagefright/MediaWriter.h> |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 24 | #include <utils/List.h> |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 25 | #include <utils/threads.h> |
| 26 | |
| 27 | namespace android { |
| 28 | |
| 29 | class MediaBuffer; |
| 30 | class MediaSource; |
| 31 | class MetaData; |
| 32 | |
Andreas Huber | 996dddf | 2010-01-25 15:30:31 -0800 | [diff] [blame] | 33 | class MPEG4Writer : public MediaWriter { |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 34 | public: |
| 35 | MPEG4Writer(const char *filename); |
Andreas Huber | ea6a38c | 2009-11-16 15:43:38 -0800 | [diff] [blame] | 36 | MPEG4Writer(int fd); |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 37 | |
Andreas Huber | 996dddf | 2010-01-25 15:30:31 -0800 | [diff] [blame] | 38 | virtual status_t addSource(const sp<MediaSource> &source); |
James Dong | 6feaa46 | 2010-06-20 08:20:54 -0700 | [diff] [blame] | 39 | virtual status_t start(MetaData *param = NULL); |
James Dong | c2240b1 | 2012-02-02 15:07:52 -0800 | [diff] [blame] | 40 | virtual status_t stop() { return reset(); } |
James Dong | d036662 | 2010-08-18 19:10:39 -0700 | [diff] [blame] | 41 | virtual status_t pause(); |
Andreas Huber | 996dddf | 2010-01-25 15:30:31 -0800 | [diff] [blame] | 42 | virtual bool reachedEOS(); |
James Dong | 3f51fa7 | 2010-08-18 03:32:26 -0700 | [diff] [blame] | 43 | virtual status_t dump(int fd, const Vector<String16>& args); |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 44 | |
| 45 | void beginBox(const char *fourcc); |
| 46 | void writeInt8(int8_t x); |
| 47 | void writeInt16(int16_t x); |
| 48 | void writeInt32(int32_t x); |
| 49 | void writeInt64(int64_t x); |
| 50 | void writeCString(const char *s); |
| 51 | void writeFourcc(const char *fourcc); |
| 52 | void write(const void *data, size_t size); |
| 53 | void endBox(); |
James Dong | 3300e96 | 2010-04-21 16:14:15 -0700 | [diff] [blame] | 54 | uint32_t interleaveDuration() const { return mInterleaveDurationUs; } |
| 55 | status_t setInterleaveDuration(uint32_t duration); |
James Dong | 52d13f0 | 2010-07-02 11:39:06 -0700 | [diff] [blame] | 56 | int32_t getTimeScale() const { return mTimeScale; } |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 57 | |
James Dong | 987ab48 | 2011-05-11 19:09:25 -0700 | [diff] [blame] | 58 | status_t setGeoData(int latitudex10000, int longitudex10000); |
James Dong | 13a3316 | 2011-05-09 16:56:25 -0700 | [diff] [blame] | 59 | void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; } |
| 60 | int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; } |
James Dong | 987ab48 | 2011-05-11 19:09:25 -0700 | [diff] [blame] | 61 | |
Andreas Huber | be06d26 | 2009-08-14 14:37:10 -0700 | [diff] [blame] | 62 | protected: |
| 63 | virtual ~MPEG4Writer(); |
| 64 | |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 65 | private: |
| 66 | class Track; |
| 67 | |
James Dong | b1262a8 | 2010-11-16 14:04:54 -0800 | [diff] [blame] | 68 | int mFd; |
James Dong | 2747e0e | 2010-11-18 20:59:13 -0800 | [diff] [blame] | 69 | status_t mInitCheck; |
James Dong | 7755cdd | 2010-09-02 10:49:55 -0700 | [diff] [blame] | 70 | bool mUse4ByteNalLength; |
James Dong | 39a0b21 | 2010-06-23 00:18:40 -0700 | [diff] [blame] | 71 | bool mUse32BitOffset; |
James Dong | 6a9e39a | 2010-10-04 16:41:53 -0700 | [diff] [blame] | 72 | bool mIsFileSizeLimitExplicitlyRequested; |
James Dong | 08c7473 | 2010-06-10 12:28:15 -0700 | [diff] [blame] | 73 | bool mPaused; |
James Dong | 0e27fce | 2011-07-08 16:51:16 -0700 | [diff] [blame] | 74 | bool mStarted; // Writer thread + track threads started successfully |
| 75 | bool mWriterThreadStarted; // Only writer thread started successfully |
James Dong | b1262a8 | 2010-11-16 14:04:54 -0800 | [diff] [blame] | 76 | off64_t mOffset; |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 77 | off_t mMdatOffset; |
James Dong | b5e7423 | 2010-05-07 10:26:24 -0700 | [diff] [blame] | 78 | uint8_t *mMoovBoxBuffer; |
James Dong | b1262a8 | 2010-11-16 14:04:54 -0800 | [diff] [blame] | 79 | off64_t mMoovBoxBufferOffset; |
James Dong | b5e7423 | 2010-05-07 10:26:24 -0700 | [diff] [blame] | 80 | bool mWriteMoovBoxToMemory; |
James Dong | b1262a8 | 2010-11-16 14:04:54 -0800 | [diff] [blame] | 81 | off64_t mFreeBoxOffset; |
James Dong | b5e7423 | 2010-05-07 10:26:24 -0700 | [diff] [blame] | 82 | bool mStreamableFile; |
James Dong | b1262a8 | 2010-11-16 14:04:54 -0800 | [diff] [blame] | 83 | off64_t mEstimatedMoovBoxSize; |
James Dong | 3300e96 | 2010-04-21 16:14:15 -0700 | [diff] [blame] | 84 | uint32_t mInterleaveDurationUs; |
James Dong | 52d13f0 | 2010-07-02 11:39:06 -0700 | [diff] [blame] | 85 | int32_t mTimeScale; |
James Dong | 9db798d | 2010-05-13 11:47:36 -0700 | [diff] [blame] | 86 | int64_t mStartTimestampUs; |
James Dong | 987ab48 | 2011-05-11 19:09:25 -0700 | [diff] [blame] | 87 | int mLatitudex10000; |
| 88 | int mLongitudex10000; |
| 89 | bool mAreGeoTagsAvailable; |
James Dong | 13a3316 | 2011-05-09 16:56:25 -0700 | [diff] [blame] | 90 | int32_t mStartTimeOffsetMs; |
James Dong | da8073c | 2010-07-30 17:41:22 -0700 | [diff] [blame] | 91 | |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 92 | Mutex mLock; |
| 93 | |
| 94 | List<Track *> mTracks; |
| 95 | |
James Dong | b1262a8 | 2010-11-16 14:04:54 -0800 | [diff] [blame] | 96 | List<off64_t> mBoxes; |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 97 | |
James Dong | 36e573b | 2010-06-19 09:04:18 -0700 | [diff] [blame] | 98 | void setStartTimestampUs(int64_t timeUs); |
| 99 | int64_t getStartTimestampUs(); // Not const |
James Dong | 09936ed | 2010-06-24 19:04:27 -0700 | [diff] [blame] | 100 | status_t startTracks(MetaData *params); |
James Dong | b54a9178 | 2010-06-22 11:27:37 -0700 | [diff] [blame] | 101 | size_t numTracks(); |
James Dong | 6feaa46 | 2010-06-20 08:20:54 -0700 | [diff] [blame] | 102 | int64_t estimateMoovBoxSize(int32_t bitRate); |
James Dong | 9db798d | 2010-05-13 11:47:36 -0700 | [diff] [blame] | 103 | |
James Dong | da8073c | 2010-07-30 17:41:22 -0700 | [diff] [blame] | 104 | struct Chunk { |
| 105 | Track *mTrack; // Owner |
| 106 | int64_t mTimeStampUs; // Timestamp of the 1st sample |
| 107 | List<MediaBuffer *> mSamples; // Sample data |
| 108 | |
| 109 | // Convenient constructor |
James Dong | f6a2bff | 2011-02-09 14:00:55 -0800 | [diff] [blame] | 110 | Chunk(): mTrack(NULL), mTimeStampUs(0) {} |
| 111 | |
James Dong | da8073c | 2010-07-30 17:41:22 -0700 | [diff] [blame] | 112 | Chunk(Track *track, int64_t timeUs, List<MediaBuffer *> samples) |
| 113 | : mTrack(track), mTimeStampUs(timeUs), mSamples(samples) { |
| 114 | } |
| 115 | |
| 116 | }; |
| 117 | struct ChunkInfo { |
| 118 | Track *mTrack; // Owner |
| 119 | List<Chunk> mChunks; // Remaining chunks to be written |
James Dong | 3aea037 | 2011-05-06 12:19:04 -0700 | [diff] [blame] | 120 | |
| 121 | // Previous chunk timestamp that has been written |
| 122 | int64_t mPrevChunkTimestampUs; |
| 123 | |
| 124 | // Max time interval between neighboring chunks |
| 125 | int64_t mMaxInterChunkDurUs; |
| 126 | |
James Dong | da8073c | 2010-07-30 17:41:22 -0700 | [diff] [blame] | 127 | }; |
| 128 | |
| 129 | bool mIsFirstChunk; |
| 130 | volatile bool mDone; // Writer thread is done? |
| 131 | pthread_t mThread; // Thread id for the writer |
| 132 | List<ChunkInfo> mChunkInfos; // Chunk infos |
| 133 | Condition mChunkReadyCondition; // Signal that chunks are available |
| 134 | |
| 135 | // Writer thread handling |
| 136 | status_t startWriterThread(); |
| 137 | void stopWriterThread(); |
| 138 | static void *ThreadWrapper(void *me); |
| 139 | void threadFunc(); |
| 140 | |
| 141 | // Buffer a single chunk to be written out later. |
| 142 | void bufferChunk(const Chunk& chunk); |
| 143 | |
| 144 | // Write all buffered chunks from all tracks |
James Dong | f6a2bff | 2011-02-09 14:00:55 -0800 | [diff] [blame] | 145 | void writeAllChunks(); |
James Dong | da8073c | 2010-07-30 17:41:22 -0700 | [diff] [blame] | 146 | |
James Dong | f6a2bff | 2011-02-09 14:00:55 -0800 | [diff] [blame] | 147 | // Retrieve the proper chunk to write if there is one |
| 148 | // Return true if a chunk is found; otherwise, return false. |
| 149 | bool findChunkToWrite(Chunk *chunk); |
James Dong | da8073c | 2010-07-30 17:41:22 -0700 | [diff] [blame] | 150 | |
James Dong | f6a2bff | 2011-02-09 14:00:55 -0800 | [diff] [blame] | 151 | // Actually write the given chunk to the file. |
| 152 | void writeChunkToFile(Chunk* chunk); |
James Dong | da8073c | 2010-07-30 17:41:22 -0700 | [diff] [blame] | 153 | |
James Dong | b720819 | 2010-08-02 19:13:40 -0700 | [diff] [blame] | 154 | // Adjust other track media clock (presumably wall clock) |
| 155 | // based on audio track media clock with the drift time. |
| 156 | int64_t mDriftTimeUs; |
James Dong | 4c23815 | 2010-09-01 18:48:35 -0700 | [diff] [blame] | 157 | void setDriftTimeUs(int64_t driftTimeUs); |
James Dong | b720819 | 2010-08-02 19:13:40 -0700 | [diff] [blame] | 158 | int64_t getDriftTimeUs(); |
| 159 | |
James Dong | 7755cdd | 2010-09-02 10:49:55 -0700 | [diff] [blame] | 160 | // Return whether the nal length is 4 bytes or 2 bytes |
| 161 | // Only makes sense for H.264/AVC |
| 162 | bool useNalLengthFour(); |
| 163 | |
James Dong | 3300e96 | 2010-04-21 16:14:15 -0700 | [diff] [blame] | 164 | void lock(); |
| 165 | void unlock(); |
| 166 | |
| 167 | // Acquire lock before calling these methods |
James Dong | b1262a8 | 2010-11-16 14:04:54 -0800 | [diff] [blame] | 168 | off64_t addSample_l(MediaBuffer *buffer); |
| 169 | off64_t addLengthPrefixedSample_l(MediaBuffer *buffer); |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 170 | |
James Dong | 2747e0e | 2010-11-18 20:59:13 -0800 | [diff] [blame] | 171 | inline size_t write(const void *ptr, size_t size, size_t nmemb); |
James Dong | 1824486 | 2010-05-11 14:57:02 -0700 | [diff] [blame] | 172 | bool exceedsFileSizeLimit(); |
James Dong | cb7e65c | 2010-09-02 11:19:11 -0700 | [diff] [blame] | 173 | bool use32BitFileOffset() const; |
James Dong | 1824486 | 2010-05-11 14:57:02 -0700 | [diff] [blame] | 174 | bool exceedsFileDurationLimit(); |
James Dong | 22b37fa | 2010-10-19 21:28:47 -0700 | [diff] [blame] | 175 | bool isFileStreamable() const; |
James Dong | 7fc8b4f | 2011-03-18 11:25:41 -0700 | [diff] [blame] | 176 | void trackProgressStatus(size_t trackId, int64_t timeUs, status_t err = OK); |
James Dong | b9d7e01 | 2010-11-09 11:15:47 -0800 | [diff] [blame] | 177 | void writeCompositionMatrix(int32_t degrees); |
James Dong | 7a6cea4 | 2011-05-06 16:55:39 -0700 | [diff] [blame] | 178 | void writeMvhdBox(int64_t durationUs); |
| 179 | void writeMoovBox(int64_t durationUs); |
James Dong | f84e4a6 | 2011-05-17 22:39:06 -0700 | [diff] [blame] | 180 | void writeFtypBox(MetaData *param); |
James Dong | 987ab48 | 2011-05-11 19:09:25 -0700 | [diff] [blame] | 181 | void writeUdtaBox(); |
| 182 | void writeGeoDataBox(); |
| 183 | void writeLatitude(int degreex10000); |
| 184 | void writeLongitude(int degreex10000); |
James Dong | 3aea037 | 2011-05-06 12:19:04 -0700 | [diff] [blame] | 185 | void sendSessionSummary(); |
James Dong | 0e27fce | 2011-07-08 16:51:16 -0700 | [diff] [blame] | 186 | void release(); |
James Dong | c2240b1 | 2012-02-02 15:07:52 -0800 | [diff] [blame] | 187 | status_t reset(); |
James Dong | b5e7423 | 2010-05-07 10:26:24 -0700 | [diff] [blame] | 188 | |
Andreas Huber | e46b7be | 2009-07-14 16:56:47 -0700 | [diff] [blame] | 189 | MPEG4Writer(const MPEG4Writer &); |
| 190 | MPEG4Writer &operator=(const MPEG4Writer &); |
| 191 | }; |
| 192 | |
| 193 | } // namespace android |
| 194 | |
| 195 | #endif // MPEG4_WRITER_H_ |