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 23 #include <media/stagefright/MediaWriter.h> 24 #include <utils/List.h> 25 #include <utils/threads.h> 26 #include <map> 27 #include <media/stagefright/foundation/AHandlerReflector.h> 28 #include <media/stagefright/foundation/ALooper.h> 29 #include <mutex> 30 #include <queue> 31 32 namespace android { 33 34 struct AMessage; 35 class MediaBuffer; 36 struct ABuffer; 37 38 class MPEG4Writer : public MediaWriter { 39 public: 40 MPEG4Writer(int fd); 41 42 // Limitations 43 // No more than one video and/or one audio source can be added, but 44 // multiple metadata sources can be added. 45 virtual status_t addSource(const sp<MediaSource> &source); 46 47 // Returns INVALID_OPERATION if there is no source or track. 48 virtual status_t start(MetaData *param = NULL); stop()49 virtual status_t stop() { return reset(); } 50 virtual status_t pause(); 51 virtual bool reachedEOS(); 52 virtual status_t dump(int fd, const Vector<String16>& args); 53 54 void beginBox(const char *fourcc); 55 void beginBox(uint32_t id); 56 void writeInt8(int8_t x); 57 void writeInt16(int16_t x); 58 void writeInt32(int32_t x); 59 void writeInt64(int64_t x); 60 void writeCString(const char *s); 61 void writeFourcc(const char *fourcc); 62 void write(const void *data, size_t size); 63 inline size_t write(const void *ptr, size_t size, size_t nmemb); 64 // Write to file system by calling ::write() or post error message to looper on failure. 65 void writeOrPostError(int fd, const void *buf, size_t count); 66 // Seek in the file by calling ::lseek64() or post error message to looper on failure. 67 void seekOrPostError(int fd, off64_t offset, int whence); 68 void endBox(); interleaveDuration()69 uint32_t interleaveDuration() const { return mInterleaveDurationUs; } 70 status_t setInterleaveDuration(uint32_t duration); getTimeScale()71 int32_t getTimeScale() const { return mTimeScale; } 72 73 status_t setGeoData(int latitudex10000, int longitudex10000); 74 status_t setCaptureRate(float captureFps); 75 status_t setTemporalLayerCount(uint32_t layerCount); 76 void notifyApproachingLimit(); setStartTimeOffsetMs(int ms)77 virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; } getStartTimeOffsetMs()78 virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; } 79 virtual status_t setNextFd(int fd); 80 81 protected: 82 virtual ~MPEG4Writer(); 83 84 private: 85 class Track; 86 friend struct AHandlerReflector<MPEG4Writer>; 87 88 enum { 89 kWhatSwitch = 'swch', 90 kWhatIOError = 'ioer', 91 kWhatFallocateError = 'faer', 92 kWhatNoIOErrorSoFar = 'noie' 93 }; 94 95 int mFd; 96 int mNextFd; 97 sp<MetaData> mStartMeta; 98 status_t mInitCheck; 99 bool mIsRealTimeRecording; 100 bool mUse4ByteNalLength; 101 bool mIsFileSizeLimitExplicitlyRequested; 102 bool mPaused; 103 bool mStarted; // Writer thread + track threads started successfully 104 bool mWriterThreadStarted; // Only writer thread started successfully 105 bool mSendNotify; 106 off64_t mOffset; 107 off64_t mPreAllocateFileEndOffset; //End of file offset during preallocation. 108 off64_t mMdatOffset; 109 off64_t mMdatEndOffset; // End offset of mdat atom. 110 uint8_t *mInMemoryCache; 111 off64_t mInMemoryCacheOffset; 112 off64_t mInMemoryCacheSize; 113 bool mWriteBoxToMemory; 114 off64_t mFreeBoxOffset; 115 bool mStreamableFile; 116 off64_t mMoovExtraSize; 117 uint32_t mInterleaveDurationUs; 118 int32_t mTimeScale; 119 int64_t mStartTimestampUs; 120 int32_t mStartTimeOffsetBFramesUs; // Longest offset needed for reordering tracks with B Frames 121 int mLatitudex10000; 122 int mLongitudex10000; 123 bool mAreGeoTagsAvailable; 124 int32_t mStartTimeOffsetMs; 125 bool mSwitchPending; 126 bool mWriteSeekErr; 127 bool mFallocateErr; 128 bool mPreAllocationEnabled; 129 // Queue to hold top long write durations 130 std::priority_queue<std::chrono::microseconds, std::vector<std::chrono::microseconds>, 131 std::greater<std::chrono::microseconds>> mWriteDurationPQ; 132 const uint8_t kWriteDurationsCount = 5; 133 134 sp<ALooper> mLooper; 135 sp<AHandlerReflector<MPEG4Writer> > mReflector; 136 137 Mutex mLock; 138 std::mutex mResetMutex; 139 std::mutex mFallocMutex; 140 bool mPreAllocFirstTime; // Pre-allocate space for file and track headers only once per file. 141 uint64_t mPrevAllTracksTotalMetaDataSizeEstimate; 142 143 List<Track *> mTracks; 144 145 List<off64_t> mBoxes; 146 147 sp<AMessage> mMetaKeys; 148 149 void setStartTimestampUs(int64_t timeUs); 150 int64_t getStartTimestampUs(); // Not const 151 int32_t getStartTimeOffsetBFramesUs(); 152 status_t startTracks(MetaData *params); 153 size_t numTracks(); 154 int64_t estimateMoovBoxSize(int32_t bitRate); 155 int64_t estimateFileLevelMetaSize(MetaData *params); 156 void writeCachedBoxToFile(const char *type); 157 void printWriteDurations(); 158 159 struct Chunk { 160 Track *mTrack; // Owner 161 int64_t mTimeStampUs; // Timestamp of the 1st sample 162 List<MediaBuffer *> mSamples; // Sample data 163 164 // Convenient constructor 165 Chunk(): mTrack(NULL), mTimeStampUs(0) {} 166 167 Chunk(Track *track, int64_t timeUs, List<MediaBuffer *> samples) 168 : mTrack(track), mTimeStampUs(timeUs), mSamples(samples) { 169 } 170 171 }; 172 struct ChunkInfo { 173 Track *mTrack; // Owner 174 List<Chunk> mChunks; // Remaining chunks to be written 175 176 // Previous chunk timestamp that has been written 177 int64_t mPrevChunkTimestampUs; 178 179 // Max time interval between neighboring chunks 180 int64_t mMaxInterChunkDurUs; 181 182 }; 183 184 bool mIsFirstChunk; 185 volatile bool mDone; // Writer thread is done? 186 pthread_t mThread; // Thread id for the writer 187 List<ChunkInfo> mChunkInfos; // Chunk infos 188 Condition mChunkReadyCondition; // Signal that chunks are available 189 190 // HEIF writing 191 typedef key_value_pair_t< const char *, Vector<uint16_t> > ItemRefs; 192 typedef struct _ItemInfo { 193 bool isGrid() const { return !strcmp("grid", itemType); } 194 bool isImage() const { return !strcmp("hvc1", itemType) || isGrid(); } 195 const char *itemType; 196 uint16_t itemId; 197 bool isPrimary; 198 bool isHidden; 199 union { 200 // image item 201 struct { 202 uint32_t offset; 203 uint32_t size; 204 }; 205 // grid item 206 struct { 207 uint32_t rows; 208 uint32_t cols; 209 uint32_t width; 210 uint32_t height; 211 }; 212 }; 213 Vector<uint16_t> properties; 214 Vector<ItemRefs> refsList; 215 } ItemInfo; 216 217 typedef struct _ItemProperty { 218 uint32_t type; 219 int32_t width; 220 int32_t height; 221 int32_t rotation; 222 sp<ABuffer> hvcc; 223 } ItemProperty; 224 225 bool mHasFileLevelMeta; 226 uint64_t mFileLevelMetaDataSize; 227 bool mHasMoovBox; 228 uint32_t mPrimaryItemId; 229 uint32_t mAssociationEntryCount; 230 uint32_t mNumGrids; 231 uint16_t mNextItemId; 232 bool mHasRefs; 233 std::map<uint32_t, ItemInfo> mItems; 234 Vector<ItemProperty> mProperties; 235 236 // Writer thread handling 237 status_t startWriterThread(); 238 status_t stopWriterThread(); 239 static void *ThreadWrapper(void *me); 240 void threadFunc(); 241 status_t setupAndStartLooper(); 242 void stopAndReleaseLooper(); 243 244 // Buffer a single chunk to be written out later. 245 void bufferChunk(const Chunk& chunk); 246 247 // Write all buffered chunks from all tracks 248 void writeAllChunks(); 249 250 // Retrieve the proper chunk to write if there is one 251 // Return true if a chunk is found; otherwise, return false. 252 bool findChunkToWrite(Chunk *chunk); 253 254 // Actually write the given chunk to the file. 255 void writeChunkToFile(Chunk* chunk); 256 257 // Adjust other track media clock (presumably wall clock) 258 // based on audio track media clock with the drift time. 259 int64_t mDriftTimeUs; 260 void setDriftTimeUs(int64_t driftTimeUs); 261 int64_t getDriftTimeUs(); 262 263 // Return whether the nal length is 4 bytes or 2 bytes 264 // Only makes sense for H.264/AVC 265 bool useNalLengthFour(); 266 267 // Return whether the writer is used for real time recording. 268 // In real time recording mode, new samples will be allowed to buffered into 269 // chunks in higher priority thread, even though the file writer has not 270 // drained the chunks yet. 271 // By default, real time recording is on. 272 bool isRealTimeRecording() const; 273 274 void lock(); 275 void unlock(); 276 277 // Init all the internal variables for each recording session. Some variables 278 // will only need to be set for the first recording session and they will stay 279 // the same across all the recording sessions. 280 void initInternal(int fd, bool isFirstSession); 281 282 // Acquire lock before calling these methods 283 off64_t addSample_l( 284 MediaBuffer *buffer, bool usePrefix, 285 uint32_t tiffHdrOffset, size_t *bytesWritten); 286 void addLengthPrefixedSample_l(MediaBuffer *buffer); 287 void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer); 288 uint16_t addProperty_l(const ItemProperty &); 289 status_t reserveItemId_l(size_t numItems, uint16_t *itemIdBase); 290 uint16_t addItem_l(const ItemInfo &); 291 void addRefs_l(uint16_t itemId, const ItemRefs &); 292 293 bool exceedsFileSizeLimit(); 294 bool exceedsFileDurationLimit(); 295 bool approachingFileSizeLimit(); 296 bool isFileStreamable() const; 297 void trackProgressStatus(uint32_t trackId, int64_t timeUs, status_t err = OK); 298 status_t validateAllTracksId(bool akKey4BitTrackIds); 299 void writeCompositionMatrix(int32_t degrees); 300 void writeMvhdBox(int64_t durationUs); 301 void writeMoovBox(int64_t durationUs); 302 void writeFtypBox(MetaData *param); 303 void writeUdtaBox(); 304 void writeGeoDataBox(); 305 void writeLatitude(int degreex10000); 306 void writeLongitude(int degreex10000); 307 void finishCurrentSession(); 308 309 void addDeviceMeta(); 310 void writeHdlr(const char *handlerType); 311 void writeKeys(); 312 void writeIlst(); 313 void writeMoovLevelMetaBox(); 314 315 /* 316 * Allocate space needed for MOOV atom in advance and maintain just enough before write 317 * of any data. Stop writing and save MOOV atom if there was any error. 318 */ 319 bool preAllocate(uint64_t wantSize); 320 /* 321 * Truncate file as per the size used for metadata and actual data in a session. 322 */ 323 bool truncatePreAllocation(); 324 325 // HEIF writing 326 void writeIlocBox(); 327 void writeInfeBox(uint16_t itemId, const char *type, uint32_t flags); 328 void writeIinfBox(); 329 void writeIpcoBox(); 330 void writeIpmaBox(); 331 void writeIprpBox(); 332 void writeIdatBox(); 333 void writeIrefBox(); 334 void writePitmBox(); 335 void writeFileLevelMetaBox(); 336 337 void sendSessionSummary(); 338 status_t release(); 339 status_t switchFd(); 340 status_t reset(bool stopSource = true); 341 342 static uint32_t getMpeg4Time(); 343 344 void onMessageReceived(const sp<AMessage> &msg); 345 346 MPEG4Writer(const MPEG4Writer &); 347 MPEG4Writer &operator=(const MPEG4Writer &); 348 }; 349 350 } // namespace android 351 352 #endif // MPEG4_WRITER_H_ 353