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 { return !strcmp("hvc1", itemType) || isGrid(); } 200 const char *itemType; 201 uint16_t itemId; 202 bool isPrimary; 203 bool isHidden; 204 union { 205 // image item 206 struct { 207 uint32_t offset; 208 uint32_t size; 209 }; 210 // grid item 211 struct { 212 uint32_t rows; 213 uint32_t cols; 214 uint32_t width; 215 uint32_t height; 216 }; 217 }; 218 Vector<uint16_t> properties; 219 Vector<ItemRefs> refsList; 220 } ItemInfo; 221 222 typedef struct _ItemProperty { 223 uint32_t type; 224 int32_t width; 225 int32_t height; 226 int32_t rotation; 227 sp<ABuffer> hvcc; 228 } ItemProperty; 229 230 bool mHasFileLevelMeta; 231 uint64_t mFileLevelMetaDataSize; 232 bool mHasMoovBox; 233 uint32_t mPrimaryItemId; 234 uint32_t mAssociationEntryCount; 235 uint32_t mNumGrids; 236 uint16_t mNextItemId; 237 bool mHasRefs; 238 std::map<uint32_t, ItemInfo> mItems; 239 Vector<ItemProperty> mProperties; 240 241 // Writer thread handling 242 status_t startWriterThread(); 243 status_t stopWriterThread(); 244 static void *ThreadWrapper(void *me); 245 void threadFunc(); 246 status_t setupAndStartLooper(); 247 void stopAndReleaseLooper(); 248 249 // Buffer a single chunk to be written out later. 250 void bufferChunk(const Chunk& chunk); 251 252 // Write all buffered chunks from all tracks 253 void writeAllChunks(); 254 255 // Retrieve the proper chunk to write if there is one 256 // Return true if a chunk is found; otherwise, return false. 257 bool findChunkToWrite(Chunk *chunk); 258 259 // Actually write the given chunk to the file. 260 void writeChunkToFile(Chunk* chunk); 261 262 // Adjust other track media clock (presumably wall clock) 263 // based on audio track media clock with the drift time. 264 int64_t mDriftTimeUs; 265 void setDriftTimeUs(int64_t driftTimeUs); 266 int64_t getDriftTimeUs(); 267 268 // Return whether the nal length is 4 bytes or 2 bytes 269 // Only makes sense for H.264/AVC 270 bool useNalLengthFour(); 271 272 // Return whether the writer is used for real time recording. 273 // In real time recording mode, new samples will be allowed to buffered into 274 // chunks in higher priority thread, even though the file writer has not 275 // drained the chunks yet. 276 // By default, real time recording is on. 277 bool isRealTimeRecording() const; 278 279 // Return whether the writer is used in background mode for media 280 // transcoding. 281 bool isBackgroundMode() const; 282 283 void lock(); 284 void unlock(); 285 286 // Init all the internal variables for each recording session. Some variables 287 // will only need to be set for the first recording session and they will stay 288 // the same across all the recording sessions. 289 void initInternal(int fd, bool isFirstSession); 290 291 // Acquire lock before calling these methods 292 off64_t addSample_l( 293 MediaBuffer *buffer, bool usePrefix, 294 uint32_t tiffHdrOffset, size_t *bytesWritten); 295 void addLengthPrefixedSample_l(MediaBuffer *buffer); 296 void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer); 297 uint16_t addProperty_l(const ItemProperty &); 298 status_t reserveItemId_l(size_t numItems, uint16_t *itemIdBase); 299 uint16_t addItem_l(const ItemInfo &); 300 void addRefs_l(uint16_t itemId, const ItemRefs &); 301 302 bool exceedsFileSizeLimit(); 303 bool exceedsFileDurationLimit(); 304 bool approachingFileSizeLimit(); 305 bool isFileStreamable() const; 306 void trackProgressStatus(uint32_t trackId, int64_t timeUs, status_t err = OK); 307 status_t validateAllTracksId(bool akKey4BitTrackIds); 308 void writeCompositionMatrix(int32_t degrees); 309 void writeMvhdBox(int64_t durationUs); 310 void writeMoovBox(int64_t durationUs); 311 void writeFtypBox(MetaData *param); 312 void writeUdtaBox(); 313 void writeGeoDataBox(); 314 void writeLatitude(int degreex10000); 315 void writeLongitude(int degreex10000); 316 status_t finishCurrentSession(); 317 318 void addDeviceMeta(); 319 void writeHdlr(const char *handlerType); 320 void writeKeys(); 321 void writeIlst(); 322 void writeMoovLevelMetaBox(); 323 324 /* 325 * Allocate space needed for MOOV atom in advance and maintain just enough before write 326 * of any data. Stop writing and save MOOV atom if there was any error. 327 */ 328 bool preAllocate(uint64_t wantSize); 329 /* 330 * Truncate file as per the size used for metadata and actual data in a session. 331 */ 332 bool truncatePreAllocation(); 333 334 // HEIF writing 335 void writeIlocBox(); 336 void writeInfeBox(uint16_t itemId, const char *type, uint32_t flags); 337 void writeIinfBox(); 338 void writeIpcoBox(); 339 void writeIpmaBox(); 340 void writeIprpBox(); 341 void writeIdatBox(); 342 void writeIrefBox(); 343 void writePitmBox(); 344 void writeFileLevelMetaBox(); 345 346 void sendSessionSummary(); 347 status_t release(); 348 status_t switchFd(); 349 status_t reset(bool stopSource = true, bool waitForAnyPreviousCallToComplete = true); 350 351 static uint32_t getMpeg4Time(); 352 353 void onMessageReceived(const sp<AMessage> &msg); 354 355 MPEG4Writer(const MPEG4Writer &); 356 MPEG4Writer &operator=(const MPEG4Writer &); 357 }; 358 359 } // namespace android 360 361 #endif // MPEG4_WRITER_H_ 362