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