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