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 Condition mFdCond; 148 149 List<Track *> mTracks; 150 151 List<off64_t> mBoxes; 152 153 sp<AMessage> mMetaKeys; 154 155 void setStartTimestampUs(int64_t timeUs); 156 int64_t getStartTimestampUs(); // Not const 157 int32_t getStartTimeOffsetBFramesUs(); 158 status_t startTracks(MetaData *params); 159 size_t numTracks(); 160 int64_t estimateMoovBoxSize(int32_t bitRate); 161 int64_t estimateFileLevelMetaSize(MetaData *params); 162 void writeCachedBoxToFile(const char *type); 163 void printWriteDurations(); 164 165 struct Chunk { 166 Track *mTrack; // Owner 167 int64_t mTimeStampUs; // Timestamp of the 1st sample 168 List<MediaBuffer *> mSamples; // Sample data 169 170 // Convenient constructor 171 Chunk(): mTrack(NULL), mTimeStampUs(0) {} 172 173 Chunk(Track *track, int64_t timeUs, List<MediaBuffer *> samples) 174 : mTrack(track), mTimeStampUs(timeUs), mSamples(samples) { 175 } 176 177 }; 178 struct ChunkInfo { 179 Track *mTrack; // Owner 180 List<Chunk> mChunks; // Remaining chunks to be written 181 182 // Previous chunk timestamp that has been written 183 int64_t mPrevChunkTimestampUs; 184 185 // Max time interval between neighboring chunks 186 int64_t mMaxInterChunkDurUs; 187 188 }; 189 190 bool mIsFirstChunk; 191 volatile bool mDone; // Writer thread is done? 192 pthread_t mThread; // Thread id for the writer 193 List<ChunkInfo> mChunkInfos; // Chunk infos 194 Condition mChunkReadyCondition; // Signal that chunks are available 195 196 // HEIF writing 197 typedef key_value_pair_t< const char *, Vector<uint16_t> > ItemRefs; 198 typedef struct _ItemInfo { 199 bool isGrid() const { return !strcmp("grid", itemType); } 200 bool isImage() const { 201 return !strcmp("hvc1", itemType) || !strcmp("av01", itemType) || isGrid(); 202 } 203 bool isGainmapMeta() const { 204 return !strcmp("tmap", itemType); 205 } 206 const char *itemType; 207 uint16_t itemId; 208 bool isPrimary; 209 bool isHidden; 210 union { 211 // image item 212 struct { 213 uint32_t offset; 214 uint32_t size; 215 }; 216 // grid item 217 struct { 218 uint32_t rows; 219 uint32_t cols; 220 uint32_t width; 221 uint32_t height; 222 }; 223 }; 224 Vector<uint16_t> properties; 225 Vector<ItemRefs> refsList; 226 } ItemInfo; 227 228 typedef struct _ItemProperty { 229 uint32_t type; 230 int32_t width; 231 int32_t height; 232 int32_t rotation; 233 int32_t colorPrimaries; 234 int32_t colorTransfer; 235 int32_t colorMatrix; 236 bool colorRange; 237 Vector<uint8_t> bitsPerChannel; 238 sp<ABuffer> data; 239 } ItemProperty; 240 241 bool mHasFileLevelMeta; 242 bool mIsAvif; // used to differentiate HEIC and AVIF under the same OUTPUT_FORMAT_HEIF 243 bool mHasGainmap; 244 uint64_t mFileLevelMetaDataSize; 245 bool mHasMoovBox; 246 uint32_t mPrimaryItemId; 247 uint32_t mAssociationEntryCount; 248 uint32_t mNumGrids; 249 uint16_t mNextItemId; 250 bool mHasRefs; 251 std::map<uint32_t, ItemInfo> mItems; 252 Vector<ItemProperty> mProperties; 253 254 bool mHasDolbyVision; 255 256 // Writer thread handling 257 status_t startWriterThread(); 258 status_t stopWriterThread(); 259 static void *ThreadWrapper(void *me); 260 void threadFunc(); 261 status_t setupAndStartLooper(); 262 void stopAndReleaseLooper(); 263 264 // Buffer a single chunk to be written out later. 265 void bufferChunk(const Chunk& chunk); 266 267 // Write all buffered chunks from all tracks 268 void writeAllChunks(); 269 270 // Retrieve the proper chunk to write if there is one 271 // Return true if a chunk is found; otherwise, return false. 272 bool findChunkToWrite(Chunk *chunk); 273 274 // Actually write the given chunk to the file. 275 void writeChunkToFile(Chunk* chunk); 276 277 // Adjust other track media clock (presumably wall clock) 278 // based on audio track media clock with the drift time. 279 int64_t mDriftTimeUs; 280 void setDriftTimeUs(int64_t driftTimeUs); 281 int64_t getDriftTimeUs(); 282 283 // Return whether the nal length is 4 bytes or 2 bytes 284 // Only makes sense for H.264/AVC 285 bool useNalLengthFour(); 286 287 // Return whether the writer is used for real time recording. 288 // In real time recording mode, new samples will be allowed to buffered into 289 // chunks in higher priority thread, even though the file writer has not 290 // drained the chunks yet. 291 // By default, real time recording is on. 292 bool isRealTimeRecording() const; 293 294 // Return whether the writer is used in background mode for media 295 // transcoding. 296 bool isBackgroundMode() const; 297 298 void lock(); 299 void unlock(); 300 301 // Init all the internal variables for each recording session. Some variables 302 // will only need to be set for the first recording session and they will stay 303 // the same across all the recording sessions. 304 void initInternal(int fd, bool isFirstSession); 305 306 // Acquire lock before calling these methods 307 off64_t addSample_l( 308 MediaBuffer *buffer, bool usePrefix, 309 uint32_t tiffHdrOffset, size_t *bytesWritten); 310 void addLengthPrefixedSample_l(MediaBuffer *buffer); 311 void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer); 312 uint16_t addProperty_l(const ItemProperty &); 313 status_t reserveItemId_l(size_t numItems, uint16_t *itemIdBase); 314 uint16_t addItem_l(const ItemInfo &); 315 void addRefs_l(uint16_t itemId, const ItemRefs &); 316 317 bool exceedsFileSizeLimit(); 318 bool exceedsFileDurationLimit(); 319 bool approachingFileSizeLimit(); 320 bool isFileStreamable() const; 321 void trackProgressStatus(uint32_t trackId, int64_t timeUs, status_t err = OK); 322 status_t validateAllTracksId(bool akKey4BitTrackIds); 323 void writeCompositionMatrix(int32_t degrees); 324 void writeMvhdBox(int64_t durationUs); 325 void writeMoovBox(int64_t durationUs); 326 void writeFtypBox(MetaData *param); 327 void writeUdtaBox(); 328 void writeGeoDataBox(); 329 void writeLatitude(int degreex10000); 330 void writeLongitude(int degreex10000); 331 status_t finishCurrentSession(); 332 333 void addDeviceMeta(); 334 void writeHdlr(const char *handlerType); 335 void writeKeys(); 336 void writeIlst(); 337 void writeMoovLevelMetaBox(); 338 339 /* 340 * Allocate space needed for MOOV atom in advance and maintain just enough before write 341 * of any data. Stop writing and save MOOV atom if there was any error. 342 */ 343 bool preAllocate(uint64_t wantSize); 344 /* 345 * Truncate file as per the size used for metadata and actual data in a session. 346 */ 347 bool truncatePreAllocation(); 348 349 // HEIF writing 350 void writeIlocBox(); 351 void writeInfeBox(uint16_t itemId, const char *type, uint32_t flags); 352 void writeIinfBox(); 353 void writeIpcoBox(); 354 void writeIpmaBox(); 355 void writeIprpBox(); 356 void writeIdatBox(); 357 void writeIrefBox(); 358 void writePitmBox(); 359 void writeGrplBox(const Vector<uint16_t> &items); 360 void writeFileLevelMetaBox(); 361 362 void sendSessionSummary(); 363 status_t release(); 364 status_t switchFd(); 365 status_t reset(bool stopSource = true, bool waitForAnyPreviousCallToComplete = true); 366 367 static uint32_t getMpeg4Time(); 368 369 void onMessageReceived(const sp<AMessage> &msg); 370 371 MPEG4Writer(const MPEG4Writer &); 372 MPEG4Writer &operator=(const MPEG4Writer &); 373 }; 374 375 } // namespace android 376 377 #endif // MPEG4_WRITER_H_ 378