content/media/encoder/fmp4_muxer/ISOControl.cpp

branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
equal deleted inserted replaced
-1:000000000000 0:921a19aa56c8
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/. */
5
6 #include <time.h>
7 #include "nsAutoPtr.h"
8 #include "ISOControl.h"
9 #include "ISOMediaBoxes.h"
10 #include "EncodedFrameContainer.h"
11
12 namespace mozilla {
13
14 // For MP4 creation_time and modification_time offset from January 1, 1904 to
15 // January 1, 1970.
16 #define iso_time_offset 2082844800
17
18 FragmentBuffer::FragmentBuffer(uint32_t aTrackType, uint32_t aFragDuration)
19 : mTrackType(aTrackType)
20 , mFragDuration(aFragDuration)
21 , mMediaStartTime(0)
22 , mFragmentNumber(0)
23 , mLastFrameTimeOfLastFragment(0)
24 , mEOS(false)
25 {
26 mFragArray.AppendElement();
27 MOZ_COUNT_CTOR(FragmentBuffer);
28 }
29
30 FragmentBuffer::~FragmentBuffer()
31 {
32 MOZ_COUNT_DTOR(FragmentBuffer);
33 }
34
35 bool
36 FragmentBuffer::HasEnoughData()
37 {
38 // Audio or video frame is enough to form a moof.
39 return (mFragArray.Length() > 1);
40 }
41
42 nsresult
43 FragmentBuffer::GetCSD(nsTArray<uint8_t>& aCSD)
44 {
45 if (!mCSDFrame) {
46 return NS_ERROR_FAILURE;
47 }
48 aCSD.AppendElements(mCSDFrame->GetFrameData().Elements(),
49 mCSDFrame->GetFrameData().Length());
50
51 return NS_OK;
52 }
53
54 nsresult
55 FragmentBuffer::AddFrame(EncodedFrame* aFrame)
56 {
57 // already EOS, it rejects all new data.
58 if (mEOS) {
59 MOZ_ASSERT(0);
60 return NS_OK;
61 }
62
63 EncodedFrame::FrameType type = aFrame->GetFrameType();
64 if (type == EncodedFrame::AAC_CSD || type == EncodedFrame::AVC_CSD ||
65 type == EncodedFrame::AMR_AUDIO_CSD) {
66 mCSDFrame = aFrame;
67 // Use CSD's timestamp as the start time. Encoder should send CSD frame first
68 // and then data frames.
69 mMediaStartTime = aFrame->GetTimeStamp();
70 mFragmentNumber = 1;
71 return NS_OK;
72 }
73
74 // if the timestamp is incorrect, abort it.
75 if (aFrame->GetTimeStamp() < mMediaStartTime) {
76 MOZ_ASSERT(false);
77 return NS_ERROR_FAILURE;
78 }
79
80 mFragArray.LastElement().AppendElement(aFrame);
81
82 // check if current fragment is reach the fragment duration.
83 if ((aFrame->GetTimeStamp() - mMediaStartTime) >= (mFragDuration * mFragmentNumber)) {
84 mFragArray.AppendElement();
85 mFragmentNumber++;
86 }
87
88 return NS_OK;
89 }
90
91 nsresult
92 FragmentBuffer::GetFirstFragment(nsTArray<nsRefPtr<EncodedFrame>>& aFragment,
93 bool aFlush)
94 {
95 // It should be called only if there is a complete fragment in mFragArray.
96 if (mFragArray.Length() <= 1 && !mEOS) {
97 MOZ_ASSERT(false);
98 return NS_ERROR_FAILURE;
99 }
100
101 if (aFlush) {
102 aFragment.SwapElements(mFragArray.ElementAt(0));
103 mFragArray.RemoveElementAt(0);
104 } else {
105 aFragment.AppendElements(mFragArray.ElementAt(0));
106 }
107 return NS_OK;
108 }
109
110 uint32_t
111 FragmentBuffer::GetFirstFragmentSampleNumber()
112 {
113 return mFragArray.ElementAt(0).Length();
114 }
115
116 uint32_t
117 FragmentBuffer::GetFirstFragmentSampleSize()
118 {
119 uint32_t size = 0;
120 uint32_t len = mFragArray.ElementAt(0).Length();
121 for (uint32_t i = 0; i < len; i++) {
122 size += mFragArray.ElementAt(0).ElementAt(i)->GetFrameData().Length();
123 }
124 return size;
125 }
126
127 ISOControl::ISOControl(uint32_t aMuxingType)
128 : mMuxingType(aMuxingType)
129 , mAudioFragmentBuffer(nullptr)
130 , mVideoFragmentBuffer(nullptr)
131 , mFragNum(0)
132 , mOutputSize(0)
133 , mBitCount(0)
134 , mBit(0)
135 {
136 // Create a data array for first mp4 Box, ftyp.
137 mOutBuffers.SetLength(1);
138 MOZ_COUNT_CTOR(ISOControl);
139 }
140
141 ISOControl::~ISOControl()
142 {
143 MOZ_COUNT_DTOR(ISOControl);
144 }
145
146 uint32_t
147 ISOControl::GetNextTrackID()
148 {
149 return (mMetaArray.Length() + 1);
150 }
151
152 uint32_t
153 ISOControl::GetTrackID(TrackMetadataBase::MetadataKind aKind)
154 {
155 for (uint32_t i = 0; i < mMetaArray.Length(); i++) {
156 if (mMetaArray[i]->GetKind() == aKind) {
157 return (i + 1);
158 }
159 }
160
161 // Track ID shouldn't be 0. It must be something wrong here.
162 MOZ_ASSERT(0);
163 return 0;
164 }
165
166 nsresult
167 ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta)
168 {
169 if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC ||
170 aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR ||
171 aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC) {
172 mMetaArray.AppendElement(aTrackMeta);
173 return NS_OK;
174 }
175 return NS_ERROR_FAILURE;
176 }
177
178 nsresult
179 ISOControl::GetAudioMetadata(nsRefPtr<AudioTrackMetadata>& aAudMeta)
180 {
181 for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
182 if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC ||
183 mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR) {
184 aAudMeta = static_cast<AudioTrackMetadata*>(mMetaArray[i].get());
185 return NS_OK;
186 }
187 }
188 return NS_ERROR_FAILURE;
189 }
190
191 nsresult
192 ISOControl::GetVideoMetadata(nsRefPtr<VideoTrackMetadata>& aVidMeta)
193 {
194 for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
195 if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AVC) {
196 aVidMeta = static_cast<VideoTrackMetadata*>(mMetaArray[i].get());
197 return NS_OK;
198 }
199 }
200 return NS_ERROR_FAILURE;
201 }
202
203 bool
204 ISOControl::HasAudioTrack()
205 {
206 nsRefPtr<AudioTrackMetadata> audMeta;
207 GetAudioMetadata(audMeta);
208 return audMeta;
209 }
210
211 bool
212 ISOControl::HasVideoTrack()
213 {
214 nsRefPtr<VideoTrackMetadata> vidMeta;
215 GetVideoMetadata(vidMeta);
216 return vidMeta;
217 }
218
219 nsresult
220 ISOControl::SetFragment(FragmentBuffer* aFragment)
221 {
222 if (aFragment->GetType() == Audio_Track) {
223 mAudioFragmentBuffer = aFragment;
224 } else {
225 mVideoFragmentBuffer = aFragment;
226 }
227 return NS_OK;
228 }
229
230 FragmentBuffer*
231 ISOControl::GetFragment(uint32_t aType)
232 {
233 if (aType == Audio_Track) {
234 return mAudioFragmentBuffer;
235 } else if (aType == Video_Track){
236 return mVideoFragmentBuffer;
237 }
238 MOZ_ASSERT(0);
239 return nullptr;
240 }
241
242 nsresult
243 ISOControl::GetBufs(nsTArray<nsTArray<uint8_t>>* aOutputBufs)
244 {
245 uint32_t len = mOutBuffers.Length();
246 for (uint32_t i = 0; i < len; i++) {
247 mOutBuffers[i].SwapElements(*aOutputBufs->AppendElement());
248 }
249 return FlushBuf();
250 }
251
252 nsresult
253 ISOControl::FlushBuf()
254 {
255 mOutBuffers.SetLength(1);
256 return NS_OK;
257 }
258
259 uint32_t
260 ISOControl::WriteAVData(nsTArray<uint8_t>& aArray)
261 {
262 MOZ_ASSERT(!mBitCount);
263
264 uint32_t len = aArray.Length();
265 if (!len) {
266 return 0;
267 }
268
269 mOutputSize += len;
270
271 // The last element already has data, allocated a new element for pointer
272 // swapping.
273 if (mOutBuffers.LastElement().Length()) {
274 mOutBuffers.AppendElement();
275 }
276 // Swap the video/audio data pointer.
277 mOutBuffers.LastElement().SwapElements(aArray);
278 // Following data could be boxes, so appending a new uint8_t array here.
279 mOutBuffers.AppendElement();
280
281 return len;
282 }
283
284 uint32_t
285 ISOControl::WriteBits(uint64_t aBits, size_t aNumBits)
286 {
287 uint8_t output_byte = 0;
288
289 MOZ_ASSERT(aNumBits <= 64);
290 // TODO: rewritten following with bitset?
291 for (size_t i = aNumBits; i > 0; i--) {
292 mBit |= (((aBits >> (i - 1)) & 1) << (8 - ++mBitCount));
293 if (mBitCount == 8) {
294 Write(&mBit, sizeof(uint8_t));
295 mBit = 0;
296 mBitCount = 0;
297 output_byte++;
298 }
299 }
300 return output_byte;
301 }
302
303 uint32_t
304 ISOControl::Write(uint8_t* aBuf, uint32_t aSize)
305 {
306 mOutBuffers.LastElement().AppendElements(aBuf, aSize);
307 mOutputSize += aSize;
308 return aSize;
309 }
310
311 uint32_t
312 ISOControl::Write(uint8_t aData)
313 {
314 MOZ_ASSERT(!mBitCount);
315 Write((uint8_t*)&aData, sizeof(uint8_t));
316 return sizeof(uint8_t);
317 }
318
319 uint32_t
320 ISOControl::GetBufPos()
321 {
322 uint32_t len = mOutBuffers.Length();
323 uint32_t pos = 0;
324 for (uint32_t i = 0; i < len; i++) {
325 pos += mOutBuffers.ElementAt(i).Length();
326 }
327 return pos;
328 }
329
330 uint32_t
331 ISOControl::WriteFourCC(const char* aType)
332 {
333 // Bit operation should be aligned to byte before writing any byte data.
334 MOZ_ASSERT(!mBitCount);
335
336 uint32_t size = strlen(aType);
337 if (size == 4) {
338 return Write((uint8_t*)aType, size);
339 }
340
341 return 0;
342 }
343
344 nsresult
345 ISOControl::GenerateFtyp()
346 {
347 nsresult rv;
348 uint32_t size;
349 nsAutoPtr<FileTypeBox> type_box(new FileTypeBox(this));
350 rv = type_box->Generate(&size);
351 NS_ENSURE_SUCCESS(rv, rv);
352 rv = type_box->Write();
353 NS_ENSURE_SUCCESS(rv, rv);
354 return NS_OK;
355 }
356
357 nsresult
358 ISOControl::GenerateMoov()
359 {
360 nsresult rv;
361 uint32_t size;
362 nsAutoPtr<MovieBox> moov_box(new MovieBox(this));
363 rv = moov_box->Generate(&size);
364 NS_ENSURE_SUCCESS(rv, rv);
365 rv = moov_box->Write();
366 NS_ENSURE_SUCCESS(rv, rv);
367 return NS_OK;
368 }
369
370 nsresult
371 ISOControl::GenerateMoof(uint32_t aTrackType)
372 {
373 mFragNum++;
374
375 nsresult rv;
376 uint32_t size;
377 uint64_t first_sample_offset = mOutputSize;
378 nsAutoPtr<MovieFragmentBox> moof_box(new MovieFragmentBox(aTrackType, this));
379 nsAutoPtr<MediaDataBox> mdat_box(new MediaDataBox(aTrackType, this));
380
381 rv = moof_box->Generate(&size);
382 NS_ENSURE_SUCCESS(rv, rv);
383 first_sample_offset += size;
384 rv = mdat_box->Generate(&size);
385 NS_ENSURE_SUCCESS(rv, rv);
386 first_sample_offset += mdat_box->FirstSampleOffsetInMediaDataBox();
387
388 // correct offset info
389 nsTArray<nsRefPtr<MuxerOperation>> tfhds;
390 rv = moof_box->Find(NS_LITERAL_CSTRING("tfhd"), tfhds);
391 NS_ENSURE_SUCCESS(rv, rv);
392 uint32_t len = tfhds.Length();
393 for (uint32_t i = 0; i < len; i++) {
394 TrackFragmentHeaderBox* tfhd = (TrackFragmentHeaderBox*) tfhds.ElementAt(i).get();
395 rv = tfhd->UpdateBaseDataOffset(first_sample_offset);
396 NS_ENSURE_SUCCESS(rv, rv);
397 }
398
399 rv = moof_box->Write();
400 NS_ENSURE_SUCCESS(rv, rv);
401 rv = mdat_box->Write();
402 NS_ENSURE_SUCCESS(rv, rv);
403
404 return NS_OK;
405 }
406
407 uint32_t
408 ISOControl::GetTime()
409 {
410 return (uint64_t)time(nullptr) + iso_time_offset;
411 }
412
413 }

mercurial