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