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