• 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     Condition mFdCond;
148 
149     List<Track *> mTracks;
150 
151     List<off64_t> mBoxes;
152 
153     sp<AMessage> mMetaKeys;
154 
155     void setStartTimestampUs(int64_t timeUs);
156     int64_t getStartTimestampUs();  // Not const
157     int32_t getStartTimeOffsetBFramesUs();
158     status_t startTracks(MetaData *params);
159     size_t numTracks();
160     int64_t estimateMoovBoxSize(int32_t bitRate);
161     int64_t estimateFileLevelMetaSize(MetaData *params);
162     void writeCachedBoxToFile(const char *type);
163     void printWriteDurations();
164 
165     struct Chunk {
166         Track               *mTrack;        // Owner
167         int64_t             mTimeStampUs;   // Timestamp of the 1st sample
168         List<MediaBuffer *> mSamples;       // Sample data
169 
170         // Convenient constructor
171         Chunk(): mTrack(NULL), mTimeStampUs(0) {}
172 
173         Chunk(Track *track, int64_t timeUs, List<MediaBuffer *> samples)
174             : mTrack(track), mTimeStampUs(timeUs), mSamples(samples) {
175         }
176 
177     };
178     struct ChunkInfo {
179         Track               *mTrack;        // Owner
180         List<Chunk>         mChunks;        // Remaining chunks to be written
181 
182         // Previous chunk timestamp that has been written
183         int64_t mPrevChunkTimestampUs;
184 
185         // Max time interval between neighboring chunks
186         int64_t mMaxInterChunkDurUs;
187 
188     };
189 
190     bool            mIsFirstChunk;
191     volatile bool   mDone;                  // Writer thread is done?
192     pthread_t       mThread;                // Thread id for the writer
193     List<ChunkInfo> mChunkInfos;            // Chunk infos
194     Condition       mChunkReadyCondition;   // Signal that chunks are available
195 
196     // HEIF writing
197     typedef key_value_pair_t< const char *, Vector<uint16_t> > ItemRefs;
198     typedef struct _ItemInfo {
199         bool isGrid() const { return !strcmp("grid", itemType); }
200         bool isImage() const {
201             return !strcmp("hvc1", itemType) || !strcmp("av01", itemType) || isGrid();
202         }
203         bool isGainmapMeta() const {
204             return !strcmp("tmap", itemType);
205         }
206         const char *itemType;
207         uint16_t itemId;
208         bool isPrimary;
209         bool isHidden;
210         union {
211             // image item
212             struct {
213                 uint32_t offset;
214                 uint32_t size;
215             };
216             // grid item
217             struct {
218                 uint32_t rows;
219                 uint32_t cols;
220                 uint32_t width;
221                 uint32_t height;
222             };
223         };
224         Vector<uint16_t> properties;
225         Vector<ItemRefs> refsList;
226     } ItemInfo;
227 
228     typedef struct _ItemProperty {
229         uint32_t type;
230         int32_t width;
231         int32_t height;
232         int32_t rotation;
233         int32_t colorPrimaries;
234         int32_t colorTransfer;
235         int32_t colorMatrix;
236         bool colorRange;
237         Vector<uint8_t> bitsPerChannel;
238         sp<ABuffer> data;
239     } ItemProperty;
240 
241     bool mHasFileLevelMeta;
242     bool mIsAvif; // used to differentiate HEIC and AVIF under the same OUTPUT_FORMAT_HEIF
243     bool mHasGainmap;
244     uint64_t mFileLevelMetaDataSize;
245     bool mHasMoovBox;
246     uint32_t mPrimaryItemId;
247     uint32_t mAssociationEntryCount;
248     uint32_t mNumGrids;
249     uint16_t mNextItemId;
250     bool mHasRefs;
251     std::map<uint32_t, ItemInfo> mItems;
252     Vector<ItemProperty> mProperties;
253 
254     bool mHasDolbyVision;
255 
256     // Writer thread handling
257     status_t startWriterThread();
258     status_t stopWriterThread();
259     static void *ThreadWrapper(void *me);
260     void threadFunc();
261     status_t setupAndStartLooper();
262     void stopAndReleaseLooper();
263 
264     // Buffer a single chunk to be written out later.
265     void bufferChunk(const Chunk& chunk);
266 
267     // Write all buffered chunks from all tracks
268     void writeAllChunks();
269 
270     // Retrieve the proper chunk to write if there is one
271     // Return true if a chunk is found; otherwise, return false.
272     bool findChunkToWrite(Chunk *chunk);
273 
274     // Actually write the given chunk to the file.
275     void writeChunkToFile(Chunk* chunk);
276 
277     // Adjust other track media clock (presumably wall clock)
278     // based on audio track media clock with the drift time.
279     int64_t mDriftTimeUs;
280     void setDriftTimeUs(int64_t driftTimeUs);
281     int64_t getDriftTimeUs();
282 
283     // Return whether the nal length is 4 bytes or 2 bytes
284     // Only makes sense for H.264/AVC
285     bool useNalLengthFour();
286 
287     // Return whether the writer is used for real time recording.
288     // In real time recording mode, new samples will be allowed to buffered into
289     // chunks in higher priority thread, even though the file writer has not
290     // drained the chunks yet.
291     // By default, real time recording is on.
292     bool isRealTimeRecording() const;
293 
294     // Return whether the writer is used in background mode for media
295     // transcoding.
296     bool isBackgroundMode() const;
297 
298     void lock();
299     void unlock();
300 
301     // Init all the internal variables for each recording session. Some variables
302     // will only need to be set for the first recording session and they will stay
303     // the same across all the recording sessions.
304     void initInternal(int fd, bool isFirstSession);
305 
306     // Acquire lock before calling these methods
307     off64_t addSample_l(
308             MediaBuffer *buffer, bool usePrefix,
309             uint32_t tiffHdrOffset, size_t *bytesWritten);
310     void addLengthPrefixedSample_l(MediaBuffer *buffer);
311     void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer);
312     uint16_t addProperty_l(const ItemProperty &);
313     status_t reserveItemId_l(size_t numItems, uint16_t *itemIdBase);
314     uint16_t addItem_l(const ItemInfo &);
315     void addRefs_l(uint16_t itemId, const ItemRefs &);
316 
317     bool exceedsFileSizeLimit();
318     bool exceedsFileDurationLimit();
319     bool approachingFileSizeLimit();
320     bool isFileStreamable() const;
321     void trackProgressStatus(uint32_t trackId, int64_t timeUs, status_t err = OK);
322     status_t validateAllTracksId(bool akKey4BitTrackIds);
323     void writeCompositionMatrix(int32_t degrees);
324     void writeMvhdBox(int64_t durationUs);
325     void writeMoovBox(int64_t durationUs);
326     void writeFtypBox(MetaData *param);
327     void writeUdtaBox();
328     void writeGeoDataBox();
329     void writeLatitude(int degreex10000);
330     void writeLongitude(int degreex10000);
331     status_t finishCurrentSession();
332 
333     void addDeviceMeta();
334     void writeHdlr(const char *handlerType);
335     void writeKeys();
336     void writeIlst();
337     void writeMoovLevelMetaBox();
338 
339     /*
340      * Allocate space needed for MOOV atom in advance and maintain just enough before write
341      * of any data.  Stop writing and save MOOV atom if there was any error.
342      */
343     bool preAllocate(uint64_t wantSize);
344     /*
345      * Truncate file as per the size used for metadata and actual data in a session.
346      */
347     bool truncatePreAllocation();
348 
349     // HEIF writing
350     void writeIlocBox();
351     void writeInfeBox(uint16_t itemId, const char *type, uint32_t flags);
352     void writeIinfBox();
353     void writeIpcoBox();
354     void writeIpmaBox();
355     void writeIprpBox();
356     void writeIdatBox();
357     void writeIrefBox();
358     void writePitmBox();
359     void writeGrplBox(const Vector<uint16_t> &items);
360     void writeFileLevelMetaBox();
361 
362     void sendSessionSummary();
363     status_t release();
364     status_t switchFd();
365     status_t reset(bool stopSource = true, bool waitForAnyPreviousCallToComplete = true);
366 
367     static uint32_t getMpeg4Time();
368 
369     void onMessageReceived(const sp<AMessage> &msg);
370 
371     MPEG4Writer(const MPEG4Writer &);
372     MPEG4Writer &operator=(const MPEG4Writer &);
373 };
374 
375 }  // namespace android
376 
377 #endif  // MPEG4_WRITER_H_
378