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); 49 virtual status_t stop(); 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 mIsBackgroundMode; 101 bool mUse4ByteNalLength; 102 bool mIsFileSizeLimitExplicitlyRequested; 103 bool mPaused; 104 bool mStarted; // Writer thread + track threads started successfully 105 bool mWriterThreadStarted; // Only writer thread started successfully 106 bool mSendNotify; 107 off64_t mOffset; 108 off64_t mPreAllocateFileEndOffset; //End of file offset during preallocation. 109 off64_t mMdatOffset; 110 off64_t mMaxOffsetAppend; // File offset written upto while appending. 111 off64_t mMdatEndOffset; // End offset of mdat atom. 112 uint8_t *mInMemoryCache; 113 off64_t mInMemoryCacheOffset; 114 off64_t mInMemoryCacheSize; 115 bool mWriteBoxToMemory; 116 off64_t mFreeBoxOffset; 117 bool mStreamableFile; 118 off64_t mMoovExtraSize; 119 uint32_t mInterleaveDurationUs; 120 int32_t mTimeScale; 121 int64_t mStartTimestampUs; 122 int32_t mStartTimeOffsetBFramesUs; // Longest offset needed for reordering tracks with B Frames 123 int mLatitudex10000; 124 int mLongitudex10000; 125 bool mAreGeoTagsAvailable; 126 int32_t mStartTimeOffsetMs; 127 bool mSwitchPending; 128 bool mWriteSeekErr; 129 bool mFallocateErr; 130 bool mPreAllocationEnabled; 131 status_t mResetStatus; 132 // Queue to hold top long write durations 133 std::priority_queue<std::chrono::microseconds, std::vector<std::chrono::microseconds>, 134 std::greater<std::chrono::microseconds>> mWriteDurationPQ; 135 const uint8_t kWriteDurationsCount = 5; 136 137 sp<ALooper> mLooper; 138 sp<AHandlerReflector<MPEG4Writer> > mReflector; 139 140 Mutex mLock; 141 // Serialize reset calls from client of MPEG4Writer and MP4WtrCtrlHlpLooper. 142 std::mutex mResetMutex; 143 // Serialize preallocation calls from different track threads. 144 std::mutex mFallocMutex; 145 bool mPreAllocFirstTime; // Pre-allocate space for file and track headers only once per file. 146 uint64_t mPrevAllTracksTotalMetaDataSizeEstimate; 147 148 List<Track *> mTracks; 149 150 List<off64_t> mBoxes; 151 152 sp<AMessage> mMetaKeys; 153 154 void setStartTimestampUs(int64_t timeUs); 155 int64_t getStartTimestampUs(); // Not const 156 int32_t getStartTimeOffsetBFramesUs(); 157 status_t startTracks(MetaData *params); 158 size_t numTracks(); 159 int64_t estimateMoovBoxSize(int32_t bitRate); 160 int64_t estimateFileLevelMetaSize(MetaData *params); 161 void writeCachedBoxToFile(const char *type); 162 void printWriteDurations(); 163 164 struct Chunk { 165 Track *mTrack; // Owner 166 int64_t mTimeStampUs; // Timestamp of the 1st sample 167 List<MediaBuffer *> mSamples; // Sample data 168 169 // Convenient constructor 170 Chunk(): mTrack(NULL), mTimeStampUs(0) {} 171 172 Chunk(Track *track, int64_t timeUs, List<MediaBuffer *> samples) 173 : mTrack(track), mTimeStampUs(timeUs), mSamples(samples) { 174 } 175 176 }; 177 struct ChunkInfo { 178 Track *mTrack; // Owner 179 List<Chunk> mChunks; // Remaining chunks to be written 180 181 // Previous chunk timestamp that has been written 182 int64_t mPrevChunkTimestampUs; 183 184 // Max time interval between neighboring chunks 185 int64_t mMaxInterChunkDurUs; 186 187 }; 188 189 bool mIsFirstChunk; 190 volatile bool mDone; // Writer thread is done? 191 pthread_t mThread; // Thread id for the writer 192 List<ChunkInfo> mChunkInfos; // Chunk infos 193 Condition mChunkReadyCondition; // Signal that chunks are available 194 195 // HEIF writing 196 typedef key_value_pair_t< const char *, Vector<uint16_t> > ItemRefs; 197 typedef struct _ItemInfo { 198 bool isGrid() const { return !strcmp("grid", itemType); } 199 bool isImage() const { 200 return !strcmp("hvc1", itemType) || !strcmp("av01", itemType) || isGrid(); 201 } 202 const char *itemType; 203 uint16_t itemId; 204 bool isPrimary; 205 bool isHidden; 206 union { 207 // image item 208 struct { 209 uint32_t offset; 210 uint32_t size; 211 }; 212 // grid item 213 struct { 214 uint32_t rows; 215 uint32_t cols; 216 uint32_t width; 217 uint32_t height; 218 }; 219 }; 220 Vector<uint16_t> properties; 221 Vector<ItemRefs> refsList; 222 } ItemInfo; 223 224 typedef struct _ItemProperty { 225 uint32_t type; 226 int32_t width; 227 int32_t height; 228 int32_t rotation; 229 sp<ABuffer> data; 230 } ItemProperty; 231 232 bool mHasFileLevelMeta; 233 bool mIsAvif; // used to differentiate HEIC and AVIF under the same OUTPUT_FORMAT_HEIF 234 uint64_t mFileLevelMetaDataSize; 235 bool mHasMoovBox; 236 uint32_t mPrimaryItemId; 237 uint32_t mAssociationEntryCount; 238 uint32_t mNumGrids; 239 uint16_t mNextItemId; 240 bool mHasRefs; 241 std::map<uint32_t, ItemInfo> mItems; 242 Vector<ItemProperty> mProperties; 243 244 bool mHasDolbyVision; 245 246 // Writer thread handling 247 status_t startWriterThread(); 248 status_t stopWriterThread(); 249 static void *ThreadWrapper(void *me); 250 void threadFunc(); 251 status_t setupAndStartLooper(); 252 void stopAndReleaseLooper(); 253 254 // Buffer a single chunk to be written out later. 255 void bufferChunk(const Chunk& chunk); 256 257 // Write all buffered chunks from all tracks 258 void writeAllChunks(); 259 260 // Retrieve the proper chunk to write if there is one 261 // Return true if a chunk is found; otherwise, return false. 262 bool findChunkToWrite(Chunk *chunk); 263 264 // Actually write the given chunk to the file. 265 void writeChunkToFile(Chunk* chunk); 266 267 // Adjust other track media clock (presumably wall clock) 268 // based on audio track media clock with the drift time. 269 int64_t mDriftTimeUs; 270 void setDriftTimeUs(int64_t driftTimeUs); 271 int64_t getDriftTimeUs(); 272 273 // Return whether the nal length is 4 bytes or 2 bytes 274 // Only makes sense for H.264/AVC 275 bool useNalLengthFour(); 276 277 // Return whether the writer is used for real time recording. 278 // In real time recording mode, new samples will be allowed to buffered into 279 // chunks in higher priority thread, even though the file writer has not 280 // drained the chunks yet. 281 // By default, real time recording is on. 282 bool isRealTimeRecording() const; 283 284 // Return whether the writer is used in background mode for media 285 // transcoding. 286 bool isBackgroundMode() const; 287 288 void lock(); 289 void unlock(); 290 291 // Init all the internal variables for each recording session. Some variables 292 // will only need to be set for the first recording session and they will stay 293 // the same across all the recording sessions. 294 void initInternal(int fd, bool isFirstSession); 295 296 // Acquire lock before calling these methods 297 off64_t addSample_l( 298 MediaBuffer *buffer, bool usePrefix, 299 uint32_t tiffHdrOffset, size_t *bytesWritten); 300 void addLengthPrefixedSample_l(MediaBuffer *buffer); 301 void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer); 302 uint16_t addProperty_l(const ItemProperty &); 303 status_t reserveItemId_l(size_t numItems, uint16_t *itemIdBase); 304 uint16_t addItem_l(const ItemInfo &); 305 void addRefs_l(uint16_t itemId, const ItemRefs &); 306 307 bool exceedsFileSizeLimit(); 308 bool exceedsFileDurationLimit(); 309 bool approachingFileSizeLimit(); 310 bool isFileStreamable() const; 311 void trackProgressStatus(uint32_t trackId, int64_t timeUs, status_t err = OK); 312 status_t validateAllTracksId(bool akKey4BitTrackIds); 313 void writeCompositionMatrix(int32_t degrees); 314 void writeMvhdBox(int64_t durationUs); 315 void writeMoovBox(int64_t durationUs); 316 void writeFtypBox(MetaData *param); 317 void writeUdtaBox(); 318 void writeGeoDataBox(); 319 void writeLatitude(int degreex10000); 320 void writeLongitude(int degreex10000); 321 status_t finishCurrentSession(); 322 323 void addDeviceMeta(); 324 void writeHdlr(const char *handlerType); 325 void writeKeys(); 326 void writeIlst(); 327 void writeMoovLevelMetaBox(); 328 329 /* 330 * Allocate space needed for MOOV atom in advance and maintain just enough before write 331 * of any data. Stop writing and save MOOV atom if there was any error. 332 */ 333 bool preAllocate(uint64_t wantSize); 334 /* 335 * Truncate file as per the size used for metadata and actual data in a session. 336 */ 337 bool truncatePreAllocation(); 338 339 // HEIF writing 340 void writeIlocBox(); 341 void writeInfeBox(uint16_t itemId, const char *type, uint32_t flags); 342 void writeIinfBox(); 343 void writeIpcoBox(); 344 void writeIpmaBox(); 345 void writeIprpBox(); 346 void writeIdatBox(); 347 void writeIrefBox(); 348 void writePitmBox(); 349 void writeFileLevelMetaBox(); 350 351 void sendSessionSummary(); 352 status_t release(); 353 status_t switchFd(); 354 status_t reset(bool stopSource = true, bool waitForAnyPreviousCallToComplete = true); 355 356 static uint32_t getMpeg4Time(); 357 358 void onMessageReceived(const sp<AMessage> &msg); 359 360 MPEG4Writer(const MPEG4Writer &); 361 MPEG4Writer &operator=(const MPEG4Writer &); 362 }; 363 364 } // namespace android 365 366 #endif // MPEG4_WRITER_H_ 367