Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef ISOCOMPOSITOR_H_
7 #define ISOCOMPOSITOR_H_
9 #include "mozilla/Endian.h"
10 #include "nsTArray.h"
11 #include "ISOTrackMetadata.h"
12 #include "EncodedFrameContainer.h"
14 namespace mozilla {
16 class Box;
17 class ISOControl;
19 /**
20 * This class collects elementary stream data to form a fragment.
21 * ISOMediaWriter will check if the data is enough; if yes, the corresponding
22 * moof will be created and write to ISOControl.
23 * Each audio and video has its own fragment and only one during the whole
24 * life cycle, when a fragment is formed in ISOControl, Flush() needs to
25 * be called to reset it.
26 */
27 class FragmentBuffer {
28 public:
29 // aTrackType: it could be Audio_Track or Video_Track.
30 // aFragDuration: it is the fragment duration. (microsecond per unit)
31 // Audio and video have the same fragment duration.
32 FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration);
33 ~FragmentBuffer();
35 // Get samples of first fragment, that will swap all the elements in the
36 // mFragArray[0] when aFlush = true, and caller is responsible for drop
37 // EncodedFrame reference count.
38 nsresult GetFirstFragment(nsTArray<nsRefPtr<EncodedFrame>>& aFragment,
39 bool aFlush = false);
41 // Add sample frame to the last element fragment of mFragArray. If sample
42 // number is enough, it will append a new fragment element. And the new
43 // sample will be added to the new fragment element of mFragArray.
44 nsresult AddFrame(EncodedFrame* aFrame);
46 // Get total sample size of first complete fragment size.
47 uint32_t GetFirstFragmentSampleSize();
49 // Get sample number of first complete fragment.
50 uint32_t GetFirstFragmentSampleNumber();
52 // Check if it accumulates enough frame data.
53 // It returns true when data is enough to form a fragment.
54 bool HasEnoughData();
56 // Called by ISOMediaWriter when TrackEncoder has sent the last frame. The
57 // remains frame data will form the last moof and move the state machine to
58 // in ISOMediaWriter to last phrase.
59 nsresult SetEndOfStream() {
60 mEOS = true;
61 return NS_OK;
62 }
63 bool EOS() { return mEOS; }
65 // CSD (codec specific data), it is generated by encoder and the data depends
66 // on codec type. This data will be sent as a special frame from encoder to
67 // ISOMediaWriter and pass to this class via AddFrame().
68 nsresult GetCSD(nsTArray<uint8_t>& aCSD);
70 bool HasCSD() { return mCSDFrame; }
72 uint32_t GetType() { return mTrackType; }
74 void SetLastFragmentLastFrameTime(uint32_t aTime) {
75 mLastFrameTimeOfLastFragment = aTime;
76 }
78 uint32_t GetLastFragmentLastFrameTime() {
79 return mLastFrameTimeOfLastFragment;
80 }
82 private:
83 uint32_t mTrackType;
85 // Fragment duration, microsecond per unit.
86 uint32_t mFragDuration;
88 // Media start time, microsecond per unit.
89 // Together with mFragDuration, mFragmentNumber and EncodedFrame->GetTimeStamp(),
90 // when the difference between current frame time and mMediaStartTime is
91 // exceeded current fragment ceiling timeframe, that means current fragment has
92 // enough data and a new element in mFragArray will be added.
93 uint64_t mMediaStartTime;
95 // Current fragment number. It will be increase when a new element of
96 // mFragArray is created.
97 // Note:
98 // It only means the fragment number of current accumulated frames, not
99 // the current 'creating' fragment mFragNum in ISOControl.
100 uint32_t mFragmentNumber;
102 // The last frame time stamp of last fragment. It is for calculating the
103 // play duration of first frame in current fragment. The frame duration is
104 // defined as "current frame timestamp - last frame timestamp" here. So it
105 // needs to keep the last timestamp of last fragment.
106 uint32_t mLastFrameTimeOfLastFragment;
108 // Array of fragments, each element has enough samples to form a
109 // complete fragment.
110 nsTArray<nsTArray<nsRefPtr<EncodedFrame>>> mFragArray;
112 // Codec specific data frame, it will be generated by encoder and send to
113 // ISOMediaWriter through WriteEncodedTrack(). The data will be vary depends
114 // on codec type.
115 nsRefPtr<EncodedFrame> mCSDFrame;
117 // END_OF_STREAM from ContainerWriter
118 bool mEOS;
119 };
121 /**
122 * ISOControl will be carried to each box when box is created. It is the main
123 * bridge for box to output stream to ContainerWriter and retrieve information.
124 * ISOControl acts 3 different roles:
125 * 1. Holds the pointer of audio metadata, video metadata, fragment and
126 * pass them to boxes.
127 * 2. Provide the functions to generate the base structure of MP4; they are
128 * GenerateFtyp, GenerateMoov, GenerateMoof, and GenerateMfra.
129 * 3. The actually writer used by MuxOperation::Write() in each box. It provides
130 * writing methods for different kind of data; they are Write, WriteArray,
131 * WriteBits...etc.
132 */
133 class ISOControl {
135 friend class Box;
137 public:
138 ISOControl(uint32_t aMuxingType);
139 ~ISOControl();
141 nsresult GenerateFtyp();
142 nsresult GenerateMoov();
143 nsresult GenerateMoof(uint32_t aTrackType);
145 // Swap elementary stream pointer to output buffers.
146 uint32_t WriteAVData(nsTArray<uint8_t>& aArray);
148 uint32_t Write(uint8_t* aBuf, uint32_t aSize);
150 uint32_t Write(uint8_t aData);
152 template <typename T>
153 uint32_t Write(T aData) {
154 MOZ_ASSERT(!mBitCount);
156 aData = NativeEndian::swapToNetworkOrder(aData);
157 Write((uint8_t*)&aData, sizeof(T));
158 return sizeof(T);
159 }
161 template <typename T>
162 uint32_t WriteArray(const T &aArray, uint32_t aSize) {
163 MOZ_ASSERT(!mBitCount);
165 uint32_t size = 0;
166 for (uint32_t i = 0; i < aSize; i++) {
167 size += Write(aArray[i]);
168 }
169 return size;
170 }
172 uint32_t WriteFourCC(const char* aType);
174 // Bit writing. Note: it needs to be byte-boundary before using
175 // others non-bit writing function.
176 uint32_t WriteBits(uint64_t aBits, size_t aNumBits);
178 // This is called by GetContainerData and swap all the buffers to aOutputBuffers.
179 nsresult GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs);
181 // Presentation time in seconds since midnight, Jan. 1, 1904, in UTC time.
182 uint32_t GetTime();
184 // current fragment number
185 uint32_t GetCurFragmentNumber() { return mFragNum; }
187 nsresult SetFragment(FragmentBuffer* aFragment);
188 FragmentBuffer* GetFragment(uint32_t aType);
190 uint32_t GetMuxingType() { return mMuxingType; }
192 nsresult SetMetadata(TrackMetadataBase* aTrackMeta);
193 nsresult GetAudioMetadata(nsRefPtr<AudioTrackMetadata>& aAudMeta);
194 nsresult GetVideoMetadata(nsRefPtr<VideoTrackMetadata>& aVidMeta);
196 // Track ID is the Metadata index in mMetaArray. It allows only 1 audio
197 // track and 1 video track in this muxer. In this muxer, it is prohibt to have
198 // mutiple audio track or video track in the same file.
199 uint32_t GetTrackID(TrackMetadataBase::MetadataKind aKind);
200 uint32_t GetNextTrackID();
202 bool HasAudioTrack();
203 bool HasVideoTrack();
205 private:
206 uint32_t GetBufPos();
207 nsresult FlushBuf();
209 // One of value in TYPE_XXX, defined in ISOMediaWriter.
210 uint32_t mMuxingType;
212 // Audio and video fragments are owned by ISOMediaWriter.
213 // They don't need to worry about pointer going stale because ISOMediaWriter's
214 // lifetime is longer than ISOControl.
215 FragmentBuffer* mAudioFragmentBuffer;
216 FragmentBuffer* mVideoFragmentBuffer;
218 // Generated fragment number
219 uint32_t mFragNum;
221 // The (index + 1) will be the track ID.
222 nsTArray<nsRefPtr<TrackMetadataBase>> mMetaArray;
224 // Array of output buffers.
225 // To save memory usage, audio/video sample will be swapped into a new element
226 // of this array.
227 //
228 // For example,
229 // mOutBuffers[0] --> boxes (allocated by muxer)
230 // mOutBuffers[1] --> video raw data (allocated by encoder)
231 // mOutBuffers[2] --> video raw data (allocated by encoder)
232 // mOutBuffers[3] --> video raw data (allocated by encoder)
233 // mOutBuffers[4] --> boxes (allocated by muxer)
234 // mOutBuffers[5] --> audio raw data (allocated by encoder)
235 // ...etc.
236 //
237 nsTArray<nsTArray<uint8_t>> mOutBuffers;
239 // Accumulate output size from Write().
240 uint64_t mOutputSize;
242 // Bit writing operation. Note: the mBitCount should be 0 before any
243 // byte-boundary writing method be called (Write(uint32_t), Write(uint16_t)...etc);
244 // otherwise, there will be assertion on these functions.
245 uint8_t mBitCount;
246 uint8_t mBit;
247 };
249 }
250 #endif