|
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 <climits> |
|
7 #include "TrackMetadataBase.h" |
|
8 #include "ISOMediaBoxes.h" |
|
9 #include "ISOControl.h" |
|
10 #include "ISOMediaWriter.h" |
|
11 #include "EncodedFrameContainer.h" |
|
12 #include "ISOTrackMetadata.h" |
|
13 #include "MP4ESDS.h" |
|
14 #include "AMRBox.h" |
|
15 #include "AVCBox.h" |
|
16 #include "VideoUtils.h" |
|
17 |
|
18 namespace mozilla { |
|
19 |
|
20 // 14496-12 6.2.2 'Data Types and fields' |
|
21 const uint32_t iso_matrix[] = { 0x00010000, 0, 0, |
|
22 0, 0x00010000, 0, |
|
23 0, 0, 0x40000000 }; |
|
24 |
|
25 uint32_t |
|
26 set_sample_flags(bool aSync) |
|
27 { |
|
28 std::bitset<32> flags; |
|
29 flags.set(16, !aSync); |
|
30 return flags.to_ulong(); |
|
31 } |
|
32 |
|
33 Box::BoxSizeChecker::BoxSizeChecker(ISOControl* aControl, uint32_t aSize) |
|
34 { |
|
35 mControl = aControl; |
|
36 ori_size = mControl->GetBufPos(); |
|
37 box_size = aSize; |
|
38 MOZ_COUNT_CTOR(BoxSizeChecker); |
|
39 } |
|
40 |
|
41 Box::BoxSizeChecker::~BoxSizeChecker() |
|
42 { |
|
43 uint32_t cur_size = mControl->GetBufPos(); |
|
44 if ((cur_size - ori_size) != box_size) { |
|
45 MOZ_ASSERT(false); |
|
46 } |
|
47 |
|
48 MOZ_COUNT_DTOR(BoxSizeChecker); |
|
49 } |
|
50 |
|
51 nsresult |
|
52 MediaDataBox::Generate(uint32_t* aBoxSize) |
|
53 { |
|
54 mFirstSampleOffset = size; |
|
55 mAllSampleSize = 0; |
|
56 |
|
57 if (mTrackType & Audio_Track) { |
|
58 FragmentBuffer* frag = mControl->GetFragment(Audio_Track); |
|
59 mAllSampleSize += frag->GetFirstFragmentSampleSize(); |
|
60 } |
|
61 if (mTrackType & Video_Track) { |
|
62 FragmentBuffer* frag = mControl->GetFragment(Video_Track); |
|
63 mAllSampleSize += frag->GetFirstFragmentSampleSize(); |
|
64 } |
|
65 |
|
66 size += mAllSampleSize; |
|
67 *aBoxSize = size; |
|
68 return NS_OK; |
|
69 } |
|
70 |
|
71 nsresult |
|
72 MediaDataBox::Write() |
|
73 { |
|
74 nsresult rv; |
|
75 BoxSizeChecker checker(mControl, size); |
|
76 Box::Write(); |
|
77 nsTArray<uint32_t> types; |
|
78 types.AppendElement(Audio_Track); |
|
79 types.AppendElement(Video_Track); |
|
80 |
|
81 for (uint32_t l = 0; l < types.Length(); l++) { |
|
82 if (mTrackType & types[l]) { |
|
83 FragmentBuffer* frag = mControl->GetFragment(types[l]); |
|
84 nsTArray<nsRefPtr<EncodedFrame>> frames; |
|
85 |
|
86 // Here is the last time we get fragment frames, flush it! |
|
87 rv = frag->GetFirstFragment(frames, true); |
|
88 NS_ENSURE_SUCCESS(rv, rv); |
|
89 |
|
90 uint32_t len = frames.Length(); |
|
91 for (uint32_t i = 0; i < len; i++) { |
|
92 nsTArray<uint8_t> frame_buffer; |
|
93 frames.ElementAt(i)->SwapOutFrameData(frame_buffer); |
|
94 mControl->WriteAVData(frame_buffer); |
|
95 } |
|
96 } |
|
97 } |
|
98 |
|
99 return NS_OK; |
|
100 } |
|
101 |
|
102 MediaDataBox::MediaDataBox(uint32_t aTrackType, ISOControl* aControl) |
|
103 : Box(NS_LITERAL_CSTRING("mdat"), aControl) |
|
104 , mAllSampleSize(0) |
|
105 , mFirstSampleOffset(0) |
|
106 , mTrackType(aTrackType) |
|
107 { |
|
108 MOZ_COUNT_CTOR(MediaDataBox); |
|
109 } |
|
110 |
|
111 MediaDataBox::~MediaDataBox() |
|
112 { |
|
113 MOZ_COUNT_DTOR(MediaDataBox); |
|
114 } |
|
115 |
|
116 uint32_t |
|
117 TrackRunBox::fillSampleTable() |
|
118 { |
|
119 uint32_t table_size = 0; |
|
120 nsresult rv; |
|
121 nsTArray<nsRefPtr<EncodedFrame>> frames; |
|
122 FragmentBuffer* frag = mControl->GetFragment(mTrackType); |
|
123 |
|
124 rv = frag->GetFirstFragment(frames); |
|
125 if (NS_FAILED(rv)) { |
|
126 return 0; |
|
127 } |
|
128 uint32_t len = frames.Length(); |
|
129 sample_info_table = new tbl[len]; |
|
130 // Create sample table according to 14496-12 8.8.8.2. |
|
131 for (uint32_t i = 0; i < len; i++) { |
|
132 // Sample size. |
|
133 sample_info_table[i].sample_size = 0; |
|
134 if (flags.to_ulong() & flags_sample_size_present) { |
|
135 sample_info_table[i].sample_size = frames.ElementAt(i)->GetFrameData().Length(); |
|
136 mAllSampleSize += sample_info_table[i].sample_size; |
|
137 table_size += sizeof(uint32_t); |
|
138 } |
|
139 |
|
140 // Sample flags. |
|
141 sample_info_table[i].sample_flags = 0; |
|
142 if (flags.to_ulong() & flags_sample_flags_present) { |
|
143 sample_info_table[i].sample_flags = |
|
144 set_sample_flags( |
|
145 (frames.ElementAt(i)->GetFrameType() == EncodedFrame::AVC_I_FRAME)); |
|
146 table_size += sizeof(uint32_t); |
|
147 } |
|
148 |
|
149 // Sample duration. |
|
150 sample_info_table[i].sample_duration = 0; |
|
151 if (flags.to_ulong() & flags_sample_duration_present) { |
|
152 // Calculate each frame's duration, it is decided by "current frame |
|
153 // timestamp - last frame timestamp". |
|
154 uint64_t frame_time = 0; |
|
155 if (i == 0) { |
|
156 frame_time = frames.ElementAt(i)->GetTimeStamp() - |
|
157 frag->GetLastFragmentLastFrameTime(); |
|
158 } else { |
|
159 frame_time = frames.ElementAt(i)->GetTimeStamp() - |
|
160 frames.ElementAt(i - 1)->GetTimeStamp(); |
|
161 // Keep the last frame time of current fagment, it will be used to calculate |
|
162 // the first frame duration of next fragment. |
|
163 if ((len - 1) == i) { |
|
164 frag->SetLastFragmentLastFrameTime(frames.ElementAt(i)->GetTimeStamp()); |
|
165 } |
|
166 } |
|
167 |
|
168 // In TrackRunBox, there should be exactly one type, either audio or video. |
|
169 MOZ_ASSERT((mTrackType & Video_Track) ^ (mTrackType & Audio_Track)); |
|
170 sample_info_table[i].sample_duration = (mTrackType & Video_Track ? |
|
171 frame_time * mVideoMeta->GetVideoClockRate() / USECS_PER_S : |
|
172 frame_time * mAudioMeta->GetAudioSampleRate() / USECS_PER_S); |
|
173 |
|
174 table_size += sizeof(uint32_t); |
|
175 } |
|
176 |
|
177 sample_info_table[i].sample_composition_time_offset = 0; |
|
178 } |
|
179 return table_size; |
|
180 } |
|
181 |
|
182 nsresult |
|
183 TrackRunBox::Generate(uint32_t* aBoxSize) |
|
184 { |
|
185 FragmentBuffer* frag = mControl->GetFragment(mTrackType); |
|
186 sample_count = frag->GetFirstFragmentSampleNumber(); |
|
187 size += sizeof(sample_count); |
|
188 |
|
189 // data_offset needs to be updated if there is other |
|
190 // TrackRunBox before this one. |
|
191 if (flags.to_ulong() & flags_data_offset_present) { |
|
192 data_offset = 0; |
|
193 size += sizeof(data_offset); |
|
194 } |
|
195 size += fillSampleTable(); |
|
196 |
|
197 *aBoxSize = size; |
|
198 |
|
199 return NS_OK; |
|
200 } |
|
201 |
|
202 nsresult |
|
203 TrackRunBox::SetDataOffset(uint32_t aOffset) |
|
204 { |
|
205 data_offset = aOffset; |
|
206 return NS_OK; |
|
207 } |
|
208 |
|
209 nsresult |
|
210 TrackRunBox::Write() |
|
211 { |
|
212 WRITE_FULLBOX(mControl, size) |
|
213 mControl->Write(sample_count); |
|
214 if (flags.to_ulong() & flags_data_offset_present) { |
|
215 mControl->Write(data_offset); |
|
216 } |
|
217 for (uint32_t i = 0; i < sample_count; i++) { |
|
218 if (flags.to_ulong() & flags_sample_duration_present) { |
|
219 mControl->Write(sample_info_table[i].sample_duration); |
|
220 } |
|
221 if (flags.to_ulong() & flags_sample_size_present) { |
|
222 mControl->Write(sample_info_table[i].sample_size); |
|
223 } |
|
224 if (flags.to_ulong() & flags_sample_flags_present) { |
|
225 mControl->Write(sample_info_table[i].sample_flags); |
|
226 } |
|
227 } |
|
228 |
|
229 return NS_OK; |
|
230 } |
|
231 |
|
232 TrackRunBox::TrackRunBox(uint32_t aType, uint32_t aFlags, ISOControl* aControl) |
|
233 : FullBox(NS_LITERAL_CSTRING("trun"), 0, aFlags, aControl) |
|
234 , sample_count(0) |
|
235 , data_offset(0) |
|
236 , first_sample_flags(0) |
|
237 , mAllSampleSize(0) |
|
238 , mTrackType(aType) |
|
239 { |
|
240 MOZ_COUNT_CTOR(TrackRunBox); |
|
241 } |
|
242 |
|
243 TrackRunBox::~TrackRunBox() |
|
244 { |
|
245 MOZ_COUNT_DTOR(TrackRunBox); |
|
246 } |
|
247 |
|
248 nsresult |
|
249 TrackFragmentHeaderBox::UpdateBaseDataOffset(uint64_t aOffset) |
|
250 { |
|
251 base_data_offset = aOffset; |
|
252 return NS_OK; |
|
253 } |
|
254 |
|
255 nsresult |
|
256 TrackFragmentHeaderBox::Generate(uint32_t* aBoxSize) |
|
257 { |
|
258 track_ID = (mTrackType == Audio_Track ? |
|
259 mControl->GetTrackID(mAudioMeta->GetKind()) : |
|
260 mControl->GetTrackID(mVideoMeta->GetKind())); |
|
261 size += sizeof(track_ID); |
|
262 |
|
263 if (flags.to_ulong() & base_data_offset_present) { |
|
264 // base_data_offset needs to add size of 'trun', 'tfhd' and |
|
265 // header of 'mdat' later. |
|
266 base_data_offset = 0; |
|
267 size += sizeof(base_data_offset); |
|
268 } |
|
269 if (flags.to_ulong() & default_sample_duration_present) { |
|
270 if (mTrackType == Video_Track) { |
|
271 if (!mVideoMeta->GetVideoFrameRate()) { |
|
272 // 0 means frame rate is variant, so it is wrong to write |
|
273 // default_sample_duration. |
|
274 MOZ_ASSERT(0); |
|
275 default_sample_duration = 0; |
|
276 } else { |
|
277 default_sample_duration = mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate(); |
|
278 } |
|
279 } else if (mTrackType == Audio_Track) { |
|
280 default_sample_duration = mAudioMeta->GetAudioFrameDuration(); |
|
281 } else { |
|
282 MOZ_ASSERT(0); |
|
283 return NS_ERROR_FAILURE; |
|
284 } |
|
285 size += sizeof(default_sample_duration); |
|
286 } |
|
287 *aBoxSize = size; |
|
288 return NS_OK; |
|
289 } |
|
290 |
|
291 nsresult |
|
292 TrackFragmentHeaderBox::Write() |
|
293 { |
|
294 WRITE_FULLBOX(mControl, size) |
|
295 mControl->Write(track_ID); |
|
296 if (flags.to_ulong() & base_data_offset_present) { |
|
297 mControl->Write(base_data_offset); |
|
298 } |
|
299 if (flags.to_ulong() & default_sample_duration_present) { |
|
300 mControl->Write(default_sample_duration); |
|
301 } |
|
302 return NS_OK; |
|
303 } |
|
304 |
|
305 TrackFragmentHeaderBox::TrackFragmentHeaderBox(uint32_t aType, |
|
306 uint32_t aFlags, |
|
307 ISOControl* aControl) |
|
308 : FullBox(NS_LITERAL_CSTRING("tfhd"), 0, aFlags, aControl) |
|
309 , track_ID(0) |
|
310 , base_data_offset(0) |
|
311 , default_sample_duration(0) |
|
312 { |
|
313 mTrackType = aType; |
|
314 MOZ_COUNT_CTOR(TrackFragmentHeaderBox); |
|
315 } |
|
316 |
|
317 TrackFragmentHeaderBox::~TrackFragmentHeaderBox() |
|
318 { |
|
319 MOZ_COUNT_DTOR(TrackFragmentHeaderBox); |
|
320 } |
|
321 |
|
322 TrackFragmentBox::TrackFragmentBox(uint32_t aType, ISOControl* aControl) |
|
323 : DefaultContainerImpl(NS_LITERAL_CSTRING("traf"), aControl) |
|
324 , mTrackType(aType) |
|
325 { |
|
326 // Flags in TrackFragmentHeaderBox. |
|
327 uint32_t tf_flags = base_data_offset_present; |
|
328 |
|
329 // Ideally, audio encoder generates audio frame in const rate. However, some |
|
330 // audio encoders don't do it so the audio frame duration needs to be checked |
|
331 // here. |
|
332 if ((mTrackType & Audio_Track) && mAudioMeta->GetAudioFrameDuration()) { |
|
333 tf_flags |= default_sample_duration_present; |
|
334 } |
|
335 |
|
336 boxes.AppendElement(new TrackFragmentHeaderBox(aType, tf_flags, aControl)); |
|
337 |
|
338 // Always adds flags_data_offset_present in each TrackRunBox, Android |
|
339 // parser requires this flag to calculate the correct bitstream offset. |
|
340 uint32_t tr_flags = flags_sample_size_present | flags_data_offset_present; |
|
341 |
|
342 // Flags in TrackRunBox. |
|
343 // If there is no default sample duration exists, each frame duration needs to |
|
344 // be recored in the TrackRunBox. |
|
345 tr_flags |= (tf_flags & default_sample_duration_present ? 0 : flags_sample_duration_present); |
|
346 |
|
347 // For video, add sample_flags to record I frame. |
|
348 tr_flags |= (mTrackType & Video_Track ? flags_sample_flags_present : 0); |
|
349 |
|
350 boxes.AppendElement(new TrackRunBox(mTrackType, tr_flags, aControl)); |
|
351 MOZ_COUNT_CTOR(TrackFragmentBox); |
|
352 } |
|
353 |
|
354 TrackFragmentBox::~TrackFragmentBox() |
|
355 { |
|
356 MOZ_COUNT_DTOR(TrackFragmentBox); |
|
357 } |
|
358 |
|
359 nsresult |
|
360 MovieFragmentHeaderBox::Generate(uint32_t* aBoxSize) |
|
361 { |
|
362 sequence_number = mControl->GetCurFragmentNumber(); |
|
363 size += sizeof(sequence_number); |
|
364 *aBoxSize = size; |
|
365 return NS_OK; |
|
366 } |
|
367 |
|
368 nsresult |
|
369 MovieFragmentHeaderBox::Write() |
|
370 { |
|
371 WRITE_FULLBOX(mControl, size) |
|
372 mControl->Write(sequence_number); |
|
373 return NS_OK; |
|
374 } |
|
375 |
|
376 MovieFragmentHeaderBox::MovieFragmentHeaderBox(uint32_t aTrackType, |
|
377 ISOControl* aControl) |
|
378 : FullBox(NS_LITERAL_CSTRING("mfhd"), 0, 0, aControl) |
|
379 , sequence_number(0) |
|
380 , mTrackType(aTrackType) |
|
381 { |
|
382 MOZ_COUNT_CTOR(MovieFragmentHeaderBox); |
|
383 } |
|
384 |
|
385 MovieFragmentHeaderBox::~MovieFragmentHeaderBox() |
|
386 { |
|
387 MOZ_COUNT_DTOR(MovieFragmentHeaderBox); |
|
388 } |
|
389 |
|
390 MovieFragmentBox::MovieFragmentBox(uint32_t aType, ISOControl* aControl) |
|
391 : DefaultContainerImpl(NS_LITERAL_CSTRING("moof"), aControl) |
|
392 , mTrackType(aType) |
|
393 { |
|
394 boxes.AppendElement(new MovieFragmentHeaderBox(mTrackType, aControl)); |
|
395 |
|
396 if (mTrackType & Audio_Track) { |
|
397 boxes.AppendElement( |
|
398 new TrackFragmentBox(Audio_Track, aControl)); |
|
399 } |
|
400 if (mTrackType & Video_Track) { |
|
401 boxes.AppendElement( |
|
402 new TrackFragmentBox(Video_Track, aControl)); |
|
403 } |
|
404 MOZ_COUNT_CTOR(MovieFragmentBox); |
|
405 } |
|
406 |
|
407 MovieFragmentBox::~MovieFragmentBox() |
|
408 { |
|
409 MOZ_COUNT_DTOR(MovieFragmentBox); |
|
410 } |
|
411 |
|
412 nsresult |
|
413 MovieFragmentBox::Generate(uint32_t* aBoxSize) |
|
414 { |
|
415 nsresult rv = DefaultContainerImpl::Generate(aBoxSize); |
|
416 NS_ENSURE_SUCCESS(rv, rv); |
|
417 |
|
418 // Correct data_offset if there are both audio and video track in |
|
419 // this fragment. This offset means the offset in the MediaDataBox. |
|
420 if (mTrackType & (Audio_Track | Video_Track)) { |
|
421 nsTArray<nsRefPtr<MuxerOperation>> truns; |
|
422 rv = Find(NS_LITERAL_CSTRING("trun"), truns); |
|
423 NS_ENSURE_SUCCESS(rv, rv); |
|
424 uint32_t len = truns.Length(); |
|
425 uint32_t data_offset = 0; |
|
426 for (uint32_t i = 0; i < len; i++) { |
|
427 TrackRunBox* trun = (TrackRunBox*) truns.ElementAt(i).get(); |
|
428 rv = trun->SetDataOffset(data_offset); |
|
429 NS_ENSURE_SUCCESS(rv, rv); |
|
430 data_offset += trun->GetAllSampleSize(); |
|
431 } |
|
432 } |
|
433 |
|
434 return NS_OK; |
|
435 } |
|
436 |
|
437 nsresult |
|
438 TrackExtendsBox::Generate(uint32_t* aBoxSize) |
|
439 { |
|
440 track_ID = (mTrackType == Audio_Track ? |
|
441 mControl->GetTrackID(mAudioMeta->GetKind()) : |
|
442 mControl->GetTrackID(mVideoMeta->GetKind())); |
|
443 |
|
444 if (mTrackType == Audio_Track) { |
|
445 default_sample_description_index = 1; |
|
446 default_sample_duration = mAudioMeta->GetAudioFrameDuration(); |
|
447 default_sample_size = mAudioMeta->GetAudioFrameSize(); |
|
448 default_sample_flags = set_sample_flags(1); |
|
449 } else if (mTrackType == Video_Track) { |
|
450 default_sample_description_index = 1; |
|
451 // Video meta data has assigned framerate, it implies that this video's |
|
452 // frame rate should be fixed. |
|
453 if (mVideoMeta->GetVideoFrameRate()) { |
|
454 default_sample_duration = |
|
455 mVideoMeta->GetVideoClockRate() / mVideoMeta->GetVideoFrameRate(); |
|
456 } |
|
457 default_sample_size = 0; |
|
458 default_sample_flags = set_sample_flags(0); |
|
459 } else { |
|
460 MOZ_ASSERT(0); |
|
461 return NS_ERROR_FAILURE; |
|
462 } |
|
463 |
|
464 size += sizeof(track_ID) + |
|
465 sizeof(default_sample_description_index) + |
|
466 sizeof(default_sample_duration) + |
|
467 sizeof(default_sample_size) + |
|
468 sizeof(default_sample_flags); |
|
469 |
|
470 *aBoxSize = size; |
|
471 |
|
472 return NS_OK; |
|
473 } |
|
474 |
|
475 nsresult |
|
476 TrackExtendsBox::Write() |
|
477 { |
|
478 WRITE_FULLBOX(mControl, size) |
|
479 mControl->Write(track_ID); |
|
480 mControl->Write(default_sample_description_index); |
|
481 mControl->Write(default_sample_duration); |
|
482 mControl->Write(default_sample_size); |
|
483 mControl->Write(default_sample_flags); |
|
484 |
|
485 return NS_OK; |
|
486 } |
|
487 |
|
488 TrackExtendsBox::TrackExtendsBox(uint32_t aType, ISOControl* aControl) |
|
489 : FullBox(NS_LITERAL_CSTRING("trex"), 0, 0, aControl) |
|
490 , track_ID(0) |
|
491 , default_sample_description_index(0) |
|
492 , default_sample_duration(0) |
|
493 , default_sample_size(0) |
|
494 , default_sample_flags(0) |
|
495 , mTrackType(aType) |
|
496 { |
|
497 MOZ_COUNT_CTOR(TrackExtendsBox); |
|
498 } |
|
499 |
|
500 TrackExtendsBox::~TrackExtendsBox() |
|
501 { |
|
502 MOZ_COUNT_DTOR(TrackExtendsBox); |
|
503 } |
|
504 |
|
505 MovieExtendsBox::MovieExtendsBox(ISOControl* aControl) |
|
506 : DefaultContainerImpl(NS_LITERAL_CSTRING("mvex"), aControl) |
|
507 { |
|
508 if (mAudioMeta) { |
|
509 boxes.AppendElement(new TrackExtendsBox(Audio_Track, aControl)); |
|
510 } |
|
511 if (mVideoMeta) { |
|
512 boxes.AppendElement(new TrackExtendsBox(Video_Track, aControl)); |
|
513 } |
|
514 MOZ_COUNT_CTOR(MovieExtendsBox); |
|
515 } |
|
516 |
|
517 MovieExtendsBox::~MovieExtendsBox() |
|
518 { |
|
519 MOZ_COUNT_DTOR(MovieExtendsBox); |
|
520 } |
|
521 |
|
522 nsresult |
|
523 ChunkOffsetBox::Generate(uint32_t* aBoxSize) |
|
524 { |
|
525 // We don't need time to sample table in fragmented mp4. |
|
526 entry_count = 0; |
|
527 size += sizeof(entry_count); |
|
528 *aBoxSize = size; |
|
529 return NS_OK; |
|
530 } |
|
531 |
|
532 nsresult |
|
533 ChunkOffsetBox::Write() |
|
534 { |
|
535 WRITE_FULLBOX(mControl, size) |
|
536 mControl->Write(entry_count); |
|
537 return NS_OK; |
|
538 } |
|
539 |
|
540 ChunkOffsetBox::ChunkOffsetBox(uint32_t aType, ISOControl* aControl) |
|
541 : FullBox(NS_LITERAL_CSTRING("stco"), 0, 0, aControl) |
|
542 , entry_count(0) |
|
543 { |
|
544 MOZ_COUNT_CTOR(ChunkOffsetBox); |
|
545 } |
|
546 |
|
547 ChunkOffsetBox::~ChunkOffsetBox() |
|
548 { |
|
549 MOZ_COUNT_DTOR(ChunkOffsetBox); |
|
550 } |
|
551 |
|
552 nsresult |
|
553 SampleToChunkBox::Generate(uint32_t* aBoxSize) |
|
554 { |
|
555 // We don't need time to sample table in fragmented mp4 |
|
556 entry_count = 0; |
|
557 size += sizeof(entry_count); |
|
558 *aBoxSize = size; |
|
559 return NS_OK; |
|
560 } |
|
561 |
|
562 nsresult |
|
563 SampleToChunkBox::Write() |
|
564 { |
|
565 WRITE_FULLBOX(mControl, size) |
|
566 mControl->Write(entry_count); |
|
567 return NS_OK; |
|
568 } |
|
569 |
|
570 SampleToChunkBox::SampleToChunkBox(uint32_t aType, ISOControl* aControl) |
|
571 : FullBox(NS_LITERAL_CSTRING("stsc"), 0, 0, aControl) |
|
572 , entry_count(0) |
|
573 { |
|
574 MOZ_COUNT_CTOR(SampleToChunkBox); |
|
575 } |
|
576 |
|
577 SampleToChunkBox::~SampleToChunkBox() |
|
578 { |
|
579 MOZ_COUNT_DTOR(SampleToChunkBox); |
|
580 } |
|
581 |
|
582 nsresult |
|
583 TimeToSampleBox::Generate(uint32_t* aBoxSize) |
|
584 { |
|
585 // We don't need time to sample table in fragmented mp4. |
|
586 entry_count = 0; |
|
587 size += sizeof(entry_count); |
|
588 *aBoxSize = size; |
|
589 return NS_OK; |
|
590 } |
|
591 |
|
592 nsresult |
|
593 TimeToSampleBox::Write() |
|
594 { |
|
595 WRITE_FULLBOX(mControl, size) |
|
596 mControl->Write(entry_count); |
|
597 return NS_OK; |
|
598 } |
|
599 |
|
600 TimeToSampleBox::TimeToSampleBox(uint32_t aType, ISOControl* aControl) |
|
601 : FullBox(NS_LITERAL_CSTRING("stts"), 0, 0, aControl) |
|
602 , entry_count(0) |
|
603 { |
|
604 MOZ_COUNT_CTOR(TimeToSampleBox); |
|
605 } |
|
606 |
|
607 TimeToSampleBox::~TimeToSampleBox() |
|
608 { |
|
609 MOZ_COUNT_DTOR(TimeToSampleBox); |
|
610 } |
|
611 |
|
612 nsresult |
|
613 SampleDescriptionBox::Generate(uint32_t* aBoxSize) |
|
614 { |
|
615 entry_count = 1; |
|
616 size += sizeof(entry_count); |
|
617 |
|
618 nsresult rv; |
|
619 uint32_t box_size; |
|
620 rv = sample_entry_box->Generate(&box_size); |
|
621 NS_ENSURE_SUCCESS(rv, rv); |
|
622 size += box_size; |
|
623 *aBoxSize = size; |
|
624 |
|
625 return NS_OK; |
|
626 } |
|
627 |
|
628 nsresult |
|
629 SampleDescriptionBox::Write() |
|
630 { |
|
631 WRITE_FULLBOX(mControl, size) |
|
632 nsresult rv; |
|
633 mControl->Write(entry_count); |
|
634 rv = sample_entry_box->Write(); |
|
635 NS_ENSURE_SUCCESS(rv, rv); |
|
636 |
|
637 return NS_OK; |
|
638 } |
|
639 |
|
640 SampleDescriptionBox::SampleDescriptionBox(uint32_t aType, ISOControl* aControl) |
|
641 : FullBox(NS_LITERAL_CSTRING("stsd"), 0, 0, aControl) |
|
642 , entry_count(0) |
|
643 { |
|
644 mTrackType = aType; |
|
645 |
|
646 switch (mTrackType) { |
|
647 case Audio_Track: |
|
648 { |
|
649 CreateAudioSampleEntry(sample_entry_box); |
|
650 } |
|
651 break; |
|
652 case Video_Track: |
|
653 { |
|
654 CreateVideoSampleEntry(sample_entry_box); |
|
655 } |
|
656 break; |
|
657 } |
|
658 MOZ_ASSERT(sample_entry_box); |
|
659 MOZ_COUNT_CTOR(SampleDescriptionBox); |
|
660 } |
|
661 |
|
662 nsresult |
|
663 SampleDescriptionBox::CreateAudioSampleEntry(nsRefPtr<SampleEntryBox>& aSampleEntry) |
|
664 { |
|
665 if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AMR) { |
|
666 aSampleEntry = new AMRSampleEntry(mControl); |
|
667 } else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AAC) { |
|
668 aSampleEntry = new MP4AudioSampleEntry(mControl); |
|
669 } else { |
|
670 MOZ_ASSERT(0); |
|
671 } |
|
672 return NS_OK; |
|
673 } |
|
674 |
|
675 nsresult |
|
676 SampleDescriptionBox::CreateVideoSampleEntry(nsRefPtr<SampleEntryBox>& aSampleEntry) |
|
677 { |
|
678 if (mVideoMeta->GetKind() == TrackMetadataBase::METADATA_AVC) { |
|
679 aSampleEntry = new AVCSampleEntry(mControl); |
|
680 } else { |
|
681 MOZ_ASSERT(0); |
|
682 } |
|
683 return NS_OK; |
|
684 } |
|
685 |
|
686 SampleDescriptionBox::~SampleDescriptionBox() |
|
687 { |
|
688 MOZ_COUNT_DTOR(SampleDescriptionBox); |
|
689 } |
|
690 |
|
691 nsresult |
|
692 SampleSizeBox::Generate(uint32_t* aBoxSize) |
|
693 { |
|
694 size += sizeof(sample_size) + |
|
695 sizeof(sample_count); |
|
696 *aBoxSize = size; |
|
697 return NS_OK; |
|
698 } |
|
699 |
|
700 nsresult |
|
701 SampleSizeBox::Write() |
|
702 { |
|
703 WRITE_FULLBOX(mControl, size) |
|
704 mControl->Write(sample_size); |
|
705 mControl->Write(sample_count); |
|
706 return NS_OK; |
|
707 } |
|
708 |
|
709 SampleSizeBox::SampleSizeBox(ISOControl* aControl) |
|
710 : FullBox(NS_LITERAL_CSTRING("stsz"), 0, 0, aControl) |
|
711 , sample_size(0) |
|
712 , sample_count(0) |
|
713 { |
|
714 MOZ_COUNT_CTOR(SampleSizeBox); |
|
715 } |
|
716 |
|
717 SampleSizeBox::~SampleSizeBox() |
|
718 { |
|
719 MOZ_COUNT_DTOR(SampleSizeBox); |
|
720 } |
|
721 |
|
722 SampleTableBox::SampleTableBox(uint32_t aType, ISOControl* aControl) |
|
723 : DefaultContainerImpl(NS_LITERAL_CSTRING("stbl"), aControl) |
|
724 { |
|
725 boxes.AppendElement(new SampleDescriptionBox(aType, aControl)); |
|
726 boxes.AppendElement(new TimeToSampleBox(aType, aControl)); |
|
727 boxes.AppendElement(new SampleToChunkBox(aType, aControl)); |
|
728 boxes.AppendElement(new SampleSizeBox(aControl)); |
|
729 boxes.AppendElement(new ChunkOffsetBox(aType, aControl)); |
|
730 MOZ_COUNT_CTOR(SampleTableBox); |
|
731 } |
|
732 |
|
733 SampleTableBox::~SampleTableBox() |
|
734 { |
|
735 MOZ_COUNT_DTOR(SampleTableBox); |
|
736 } |
|
737 |
|
738 nsresult |
|
739 DataEntryUrlBox::Generate(uint32_t* aBoxSize) |
|
740 { |
|
741 // location is null here, do nothing |
|
742 size += location.Length(); |
|
743 *aBoxSize = size; |
|
744 |
|
745 return NS_OK; |
|
746 } |
|
747 |
|
748 nsresult |
|
749 DataEntryUrlBox::Write() |
|
750 { |
|
751 WRITE_FULLBOX(mControl, size) |
|
752 return NS_OK; |
|
753 } |
|
754 |
|
755 DataEntryUrlBox::DataEntryUrlBox() |
|
756 : FullBox(NS_LITERAL_CSTRING("url "), 0, 0, (ISOControl*) nullptr) |
|
757 { |
|
758 MOZ_COUNT_CTOR(DataEntryUrlBox); |
|
759 } |
|
760 |
|
761 DataEntryUrlBox::DataEntryUrlBox(ISOControl* aControl) |
|
762 : FullBox(NS_LITERAL_CSTRING("url "), 0, flags_media_at_the_same_file, aControl) |
|
763 { |
|
764 MOZ_COUNT_CTOR(DataEntryUrlBox); |
|
765 } |
|
766 |
|
767 DataEntryUrlBox::DataEntryUrlBox(const DataEntryUrlBox& aBox) |
|
768 : FullBox(aBox.boxType, aBox.version, aBox.flags.to_ulong(), aBox.mControl) |
|
769 { |
|
770 location = aBox.location; |
|
771 MOZ_COUNT_CTOR(DataEntryUrlBox); |
|
772 } |
|
773 |
|
774 DataEntryUrlBox::~DataEntryUrlBox() |
|
775 { |
|
776 MOZ_COUNT_DTOR(DataEntryUrlBox); |
|
777 } |
|
778 |
|
779 nsresult DataReferenceBox::Generate(uint32_t* aBoxSize) |
|
780 { |
|
781 entry_count = 1; // only allow on entry here |
|
782 size += sizeof(uint32_t); |
|
783 |
|
784 for (uint32_t i = 0; i < entry_count; i++) { |
|
785 uint32_t box_size = 0; |
|
786 DataEntryUrlBox* url = new DataEntryUrlBox(mControl); |
|
787 url->Generate(&box_size); |
|
788 size += box_size; |
|
789 urls.AppendElement(url); |
|
790 } |
|
791 |
|
792 *aBoxSize = size; |
|
793 |
|
794 return NS_OK; |
|
795 } |
|
796 |
|
797 nsresult DataReferenceBox::Write() |
|
798 { |
|
799 WRITE_FULLBOX(mControl, size) |
|
800 mControl->Write(entry_count); |
|
801 |
|
802 for (uint32_t i = 0; i < entry_count; i++) { |
|
803 urls[i]->Write(); |
|
804 } |
|
805 |
|
806 return NS_OK; |
|
807 } |
|
808 |
|
809 DataReferenceBox::DataReferenceBox(ISOControl* aControl) |
|
810 : FullBox(NS_LITERAL_CSTRING("dref"), 0, 0, aControl) |
|
811 , entry_count(0) |
|
812 { |
|
813 MOZ_COUNT_CTOR(DataReferenceBox); |
|
814 } |
|
815 |
|
816 DataReferenceBox::~DataReferenceBox() |
|
817 { |
|
818 MOZ_COUNT_DTOR(DataReferenceBox); |
|
819 } |
|
820 |
|
821 DataInformationBox::DataInformationBox(ISOControl* aControl) |
|
822 : DefaultContainerImpl(NS_LITERAL_CSTRING("dinf"), aControl) |
|
823 { |
|
824 boxes.AppendElement(new DataReferenceBox(aControl)); |
|
825 MOZ_COUNT_CTOR(DataInformationBox); |
|
826 } |
|
827 |
|
828 DataInformationBox::~DataInformationBox() |
|
829 { |
|
830 MOZ_COUNT_DTOR(DataInformationBox); |
|
831 } |
|
832 |
|
833 nsresult |
|
834 VideoMediaHeaderBox::Generate(uint32_t* aBoxSize) |
|
835 { |
|
836 size += sizeof(graphicsmode) + |
|
837 sizeof(opcolor); |
|
838 |
|
839 *aBoxSize = size; |
|
840 |
|
841 return NS_OK; |
|
842 } |
|
843 |
|
844 nsresult |
|
845 VideoMediaHeaderBox::Write() |
|
846 { |
|
847 WRITE_FULLBOX(mControl, size) |
|
848 mControl->Write(graphicsmode); |
|
849 mControl->WriteArray(opcolor, 3); |
|
850 return NS_OK; |
|
851 } |
|
852 |
|
853 VideoMediaHeaderBox::VideoMediaHeaderBox(ISOControl* aControl) |
|
854 : FullBox(NS_LITERAL_CSTRING("vmhd"), 0, 1, aControl) |
|
855 , graphicsmode(0) |
|
856 { |
|
857 memset(opcolor, 0 , sizeof(opcolor)); |
|
858 MOZ_COUNT_CTOR(VideoMediaHeaderBox); |
|
859 } |
|
860 |
|
861 VideoMediaHeaderBox::~VideoMediaHeaderBox() |
|
862 { |
|
863 MOZ_COUNT_DTOR(VideoMediaHeaderBox); |
|
864 } |
|
865 |
|
866 nsresult |
|
867 SoundMediaHeaderBox::Generate(uint32_t* aBoxSize) |
|
868 { |
|
869 balance = 0; |
|
870 reserved = 0; |
|
871 size += sizeof(balance) + |
|
872 sizeof(reserved); |
|
873 |
|
874 *aBoxSize = size; |
|
875 |
|
876 return NS_OK; |
|
877 } |
|
878 |
|
879 nsresult |
|
880 SoundMediaHeaderBox::Write() |
|
881 { |
|
882 WRITE_FULLBOX(mControl, size) |
|
883 mControl->Write(balance); |
|
884 mControl->Write(reserved); |
|
885 |
|
886 return NS_OK; |
|
887 } |
|
888 |
|
889 SoundMediaHeaderBox::SoundMediaHeaderBox(ISOControl* aControl) |
|
890 : FullBox(NS_LITERAL_CSTRING("smhd"), 0, 0, aControl) |
|
891 { |
|
892 MOZ_COUNT_CTOR(SoundMediaHeaderBox); |
|
893 } |
|
894 |
|
895 SoundMediaHeaderBox::~SoundMediaHeaderBox() |
|
896 { |
|
897 MOZ_COUNT_DTOR(SoundMediaHeaderBox); |
|
898 } |
|
899 |
|
900 MediaInformationBox::MediaInformationBox(uint32_t aType, ISOControl* aControl) |
|
901 : DefaultContainerImpl(NS_LITERAL_CSTRING("minf"), aControl) |
|
902 { |
|
903 mTrackType = aType; |
|
904 |
|
905 if (mTrackType == Audio_Track) { |
|
906 boxes.AppendElement(new SoundMediaHeaderBox(aControl)); |
|
907 } else if (mTrackType == Video_Track) { |
|
908 boxes.AppendElement(new VideoMediaHeaderBox(aControl)); |
|
909 } else { |
|
910 MOZ_ASSERT(0); |
|
911 } |
|
912 |
|
913 boxes.AppendElement(new DataInformationBox(aControl)); |
|
914 boxes.AppendElement(new SampleTableBox(aType, aControl)); |
|
915 MOZ_COUNT_CTOR(MediaInformationBox); |
|
916 } |
|
917 |
|
918 MediaInformationBox::~MediaInformationBox() |
|
919 { |
|
920 MOZ_COUNT_DTOR(MediaInformationBox); |
|
921 } |
|
922 |
|
923 nsresult |
|
924 HandlerBox::Generate(uint32_t* aBoxSize) |
|
925 { |
|
926 pre_defined = 0; |
|
927 if (mTrackType == Audio_Track) { |
|
928 handler_type = FOURCC('s', 'o', 'u', 'n'); |
|
929 } else if (mTrackType == Video_Track) { |
|
930 handler_type = FOURCC('v', 'i', 'd', 'e'); |
|
931 } |
|
932 |
|
933 size += sizeof(pre_defined) + |
|
934 sizeof(handler_type) + |
|
935 sizeof(reserved); |
|
936 |
|
937 *aBoxSize = size; |
|
938 |
|
939 return NS_OK; |
|
940 } |
|
941 |
|
942 nsresult |
|
943 HandlerBox::Write() |
|
944 { |
|
945 WRITE_FULLBOX(mControl, size) |
|
946 mControl->Write(pre_defined); |
|
947 mControl->Write(handler_type); |
|
948 mControl->WriteArray(reserved, 3); |
|
949 |
|
950 return NS_OK; |
|
951 } |
|
952 |
|
953 HandlerBox::HandlerBox(uint32_t aType, ISOControl* aControl) |
|
954 : FullBox(NS_LITERAL_CSTRING("hdlr"), 0, 0, aControl) |
|
955 , pre_defined(0) |
|
956 , handler_type(0) |
|
957 { |
|
958 mTrackType = aType; |
|
959 memset(reserved, 0 , sizeof(reserved)); |
|
960 MOZ_COUNT_CTOR(HandlerBox); |
|
961 } |
|
962 |
|
963 HandlerBox::~HandlerBox() |
|
964 { |
|
965 MOZ_COUNT_DTOR(HandlerBox); |
|
966 } |
|
967 |
|
968 MediaHeaderBox::MediaHeaderBox(uint32_t aType, ISOControl* aControl) |
|
969 : FullBox(NS_LITERAL_CSTRING("mdhd"), 0, 0, aControl) |
|
970 , creation_time(0) |
|
971 , modification_time(0) |
|
972 , timescale(0) |
|
973 , duration(0) |
|
974 , pad(0) |
|
975 , lang1(0) |
|
976 , lang2(0) |
|
977 , lang3(0) |
|
978 , pre_defined(0) |
|
979 { |
|
980 mTrackType = aType; |
|
981 MOZ_COUNT_CTOR(MediaHeaderBox); |
|
982 } |
|
983 |
|
984 MediaHeaderBox::~MediaHeaderBox() |
|
985 { |
|
986 MOZ_COUNT_DTOR(MediaHeaderBox); |
|
987 } |
|
988 |
|
989 uint32_t |
|
990 MediaHeaderBox::GetTimeScale() |
|
991 { |
|
992 if (mTrackType == Audio_Track) { |
|
993 return mAudioMeta->GetAudioSampleRate(); |
|
994 } |
|
995 |
|
996 return mVideoMeta->GetVideoClockRate(); |
|
997 } |
|
998 |
|
999 nsresult |
|
1000 MediaHeaderBox::Generate(uint32_t* aBoxSize) |
|
1001 { |
|
1002 creation_time = mControl->GetTime(); |
|
1003 modification_time = mControl->GetTime(); |
|
1004 timescale = GetTimeScale(); |
|
1005 duration = 0; // fragmented mp4 |
|
1006 |
|
1007 pad = 0; |
|
1008 lang1 = 'u' - 0x60; // "und" underdetermined language |
|
1009 lang2 = 'n' - 0x60; |
|
1010 lang3 = 'd' - 0x60; |
|
1011 size += (pad.size() + lang1.size() + lang2.size() + lang3.size()) / CHAR_BIT; |
|
1012 |
|
1013 pre_defined = 0; |
|
1014 size += sizeof(creation_time) + |
|
1015 sizeof(modification_time) + |
|
1016 sizeof(timescale) + |
|
1017 sizeof(duration) + |
|
1018 sizeof(pre_defined); |
|
1019 |
|
1020 *aBoxSize = size; |
|
1021 |
|
1022 return NS_OK; |
|
1023 } |
|
1024 |
|
1025 nsresult |
|
1026 MediaHeaderBox::Write() |
|
1027 { |
|
1028 WRITE_FULLBOX(mControl, size) |
|
1029 mControl->Write(creation_time); |
|
1030 mControl->Write(modification_time); |
|
1031 mControl->Write(timescale); |
|
1032 mControl->Write(duration); |
|
1033 mControl->WriteBits(pad.to_ulong(), pad.size()); |
|
1034 mControl->WriteBits(lang1.to_ulong(), lang1.size()); |
|
1035 mControl->WriteBits(lang2.to_ulong(), lang2.size()); |
|
1036 mControl->WriteBits(lang3.to_ulong(), lang3.size()); |
|
1037 mControl->Write(pre_defined); |
|
1038 |
|
1039 return NS_OK; |
|
1040 } |
|
1041 |
|
1042 MovieBox::MovieBox(ISOControl* aControl) |
|
1043 : DefaultContainerImpl(NS_LITERAL_CSTRING("moov"), aControl) |
|
1044 { |
|
1045 boxes.AppendElement(new MovieHeaderBox(aControl)); |
|
1046 if (aControl->HasAudioTrack()) { |
|
1047 boxes.AppendElement(new TrackBox(Audio_Track, aControl)); |
|
1048 } |
|
1049 if (aControl->HasVideoTrack()) { |
|
1050 boxes.AppendElement(new TrackBox(Video_Track, aControl)); |
|
1051 } |
|
1052 boxes.AppendElement(new MovieExtendsBox(aControl)); |
|
1053 MOZ_COUNT_CTOR(MovieBox); |
|
1054 } |
|
1055 |
|
1056 MovieBox::~MovieBox() |
|
1057 { |
|
1058 MOZ_COUNT_DTOR(MovieBox); |
|
1059 } |
|
1060 |
|
1061 nsresult |
|
1062 MovieHeaderBox::Generate(uint32_t* aBoxSize) |
|
1063 { |
|
1064 creation_time = mControl->GetTime(); |
|
1065 modification_time = mControl->GetTime(); |
|
1066 timescale = GetTimeScale(); |
|
1067 duration = 0; // The duration is always 0 in fragmented mp4. |
|
1068 next_track_ID = mControl->GetNextTrackID(); |
|
1069 |
|
1070 size += sizeof(next_track_ID) + |
|
1071 sizeof(creation_time) + |
|
1072 sizeof(modification_time) + |
|
1073 sizeof(timescale) + |
|
1074 sizeof(duration) + |
|
1075 sizeof(rate) + |
|
1076 sizeof(volume) + |
|
1077 sizeof(reserved16) + |
|
1078 sizeof(reserved32) + |
|
1079 sizeof(matrix) + |
|
1080 sizeof(pre_defined); |
|
1081 |
|
1082 *aBoxSize = size; |
|
1083 |
|
1084 return NS_OK; |
|
1085 } |
|
1086 |
|
1087 nsresult |
|
1088 MovieHeaderBox::Write() |
|
1089 { |
|
1090 WRITE_FULLBOX(mControl, size) |
|
1091 mControl->Write(creation_time); |
|
1092 mControl->Write(modification_time); |
|
1093 mControl->Write(timescale); |
|
1094 mControl->Write(duration); |
|
1095 mControl->Write(rate); |
|
1096 mControl->Write(volume); |
|
1097 mControl->Write(reserved16); |
|
1098 mControl->WriteArray(reserved32, 2); |
|
1099 mControl->WriteArray(matrix, 9); |
|
1100 mControl->WriteArray(pre_defined, 6); |
|
1101 mControl->Write(next_track_ID); |
|
1102 |
|
1103 return NS_OK; |
|
1104 } |
|
1105 |
|
1106 uint32_t |
|
1107 MovieHeaderBox::GetTimeScale() |
|
1108 { |
|
1109 // Only audio track in container. |
|
1110 if (mAudioMeta && !mVideoMeta) { |
|
1111 return mAudioMeta->GetAudioSampleRate(); |
|
1112 } |
|
1113 |
|
1114 // return video rate |
|
1115 return mVideoMeta->GetVideoClockRate(); |
|
1116 } |
|
1117 |
|
1118 MovieHeaderBox::~MovieHeaderBox() |
|
1119 { |
|
1120 MOZ_COUNT_DTOR(MovieHeaderBox); |
|
1121 } |
|
1122 |
|
1123 MovieHeaderBox::MovieHeaderBox(ISOControl* aControl) |
|
1124 : FullBox(NS_LITERAL_CSTRING("mvhd"), 0, 0, aControl) |
|
1125 , creation_time(0) |
|
1126 , modification_time(0) |
|
1127 , timescale(90000) |
|
1128 , duration(0) |
|
1129 , rate(0x00010000) |
|
1130 , volume(0x0100) |
|
1131 , reserved16(0) |
|
1132 , next_track_ID(1) |
|
1133 { |
|
1134 memcpy(matrix, iso_matrix, sizeof(matrix)); |
|
1135 memset(reserved32, 0, sizeof(reserved32)); |
|
1136 memset(pre_defined, 0, sizeof(pre_defined)); |
|
1137 MOZ_COUNT_CTOR(MovieHeaderBox); |
|
1138 } |
|
1139 |
|
1140 TrackHeaderBox::TrackHeaderBox(uint32_t aType, ISOControl* aControl) |
|
1141 : FullBox(NS_LITERAL_CSTRING("tkhd"), 0, |
|
1142 flags_track_enabled | flags_track_in_movie | flags_track_in_preview, |
|
1143 aControl) |
|
1144 , creation_time(0) |
|
1145 , modification_time(0) |
|
1146 , track_ID(0) |
|
1147 , reserved(0) |
|
1148 , duration(0) |
|
1149 , layer(0) |
|
1150 , alternate_group(0) |
|
1151 , volume(0) |
|
1152 , reserved3(0) |
|
1153 , width(0) |
|
1154 , height(0) |
|
1155 { |
|
1156 mTrackType = aType; |
|
1157 memcpy(matrix, iso_matrix, sizeof(matrix)); |
|
1158 memset(reserved2, 0, sizeof(reserved2)); |
|
1159 MOZ_COUNT_CTOR(TrackHeaderBox); |
|
1160 } |
|
1161 |
|
1162 TrackHeaderBox::~TrackHeaderBox() |
|
1163 { |
|
1164 MOZ_COUNT_DTOR(TrackHeaderBox); |
|
1165 } |
|
1166 |
|
1167 nsresult |
|
1168 TrackHeaderBox::Generate(uint32_t* aBoxSize) |
|
1169 { |
|
1170 creation_time = mControl->GetTime(); |
|
1171 modification_time = mControl->GetTime(); |
|
1172 track_ID = (mTrackType == Audio_Track ? |
|
1173 mControl->GetTrackID(mAudioMeta->GetKind()) : |
|
1174 mControl->GetTrackID(mVideoMeta->GetKind())); |
|
1175 // fragmented mp4 |
|
1176 duration = 0; |
|
1177 |
|
1178 // volume, audiotrack is always 0x0100 in 14496-12 8.3.2.2 |
|
1179 volume = (mTrackType == Audio_Track ? 0x0100 : 0); |
|
1180 |
|
1181 if (mTrackType == Video_Track) { |
|
1182 width = mVideoMeta->GetVideoDisplayWidth() << 16; |
|
1183 height = mVideoMeta->GetVideoDisplayHeight() << 16; |
|
1184 // Check display size, using the pixel size if any of them is invalid. |
|
1185 if (!width || !height) { |
|
1186 width = mVideoMeta->GetVideoWidth() << 16; |
|
1187 height = mVideoMeta->GetVideoHeight() << 16; |
|
1188 } |
|
1189 } |
|
1190 |
|
1191 size += sizeof(creation_time) + |
|
1192 sizeof(modification_time) + |
|
1193 sizeof(track_ID) + |
|
1194 sizeof(reserved) + |
|
1195 sizeof(duration) + |
|
1196 sizeof(reserved2) + |
|
1197 sizeof(layer) + |
|
1198 sizeof(alternate_group) + |
|
1199 sizeof(volume) + |
|
1200 sizeof(reserved3) + |
|
1201 sizeof(matrix) + |
|
1202 sizeof(width) + |
|
1203 sizeof(height); |
|
1204 |
|
1205 *aBoxSize = size; |
|
1206 |
|
1207 return NS_OK; |
|
1208 } |
|
1209 |
|
1210 nsresult |
|
1211 TrackHeaderBox::Write() |
|
1212 { |
|
1213 WRITE_FULLBOX(mControl, size) |
|
1214 mControl->Write(creation_time); |
|
1215 mControl->Write(modification_time); |
|
1216 mControl->Write(track_ID); |
|
1217 mControl->Write(reserved); |
|
1218 mControl->Write(duration); |
|
1219 mControl->WriteArray(reserved2, 2); |
|
1220 mControl->Write(layer); |
|
1221 mControl->Write(alternate_group); |
|
1222 mControl->Write(volume); |
|
1223 mControl->Write(reserved3); |
|
1224 mControl->WriteArray(matrix, 9); |
|
1225 mControl->Write(width); |
|
1226 mControl->Write(height); |
|
1227 |
|
1228 return NS_OK; |
|
1229 } |
|
1230 |
|
1231 nsresult |
|
1232 FileTypeBox::Generate(uint32_t* aBoxSize) |
|
1233 { |
|
1234 minor_version = 0; |
|
1235 |
|
1236 if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_MP4) { |
|
1237 if (!mControl->HasVideoTrack() && mControl->HasAudioTrack()) { |
|
1238 major_brand = "M4A "; |
|
1239 } else { |
|
1240 major_brand = "MP42"; |
|
1241 } |
|
1242 compatible_brands.AppendElement("mp42"); |
|
1243 compatible_brands.AppendElement("isom"); |
|
1244 } else if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_3GP) { |
|
1245 major_brand = "3gp9"; |
|
1246 // According to 3GPP TS 26.244 V12.2.0, section 5.3.4, it's recommended to |
|
1247 // list all compatible brands here. 3GP spec supports fragment from '3gp6'. |
|
1248 compatible_brands.AppendElement("3gp9"); |
|
1249 compatible_brands.AppendElement("3gp8"); |
|
1250 compatible_brands.AppendElement("3gp7"); |
|
1251 compatible_brands.AppendElement("3gp6"); |
|
1252 compatible_brands.AppendElement("isom"); |
|
1253 } else { |
|
1254 MOZ_ASSERT(0); |
|
1255 } |
|
1256 |
|
1257 size += major_brand.Length() + |
|
1258 sizeof(minor_version) + |
|
1259 compatible_brands.Length() * 4; |
|
1260 |
|
1261 *aBoxSize = size; |
|
1262 |
|
1263 return NS_OK; |
|
1264 } |
|
1265 |
|
1266 nsresult |
|
1267 FileTypeBox::Write() |
|
1268 { |
|
1269 BoxSizeChecker checker(mControl, size); |
|
1270 Box::Write(); |
|
1271 mControl->WriteFourCC(major_brand.get()); |
|
1272 mControl->Write(minor_version); |
|
1273 uint32_t len = compatible_brands.Length(); |
|
1274 for (uint32_t i = 0; i < len; i++) { |
|
1275 mControl->WriteFourCC(compatible_brands[i].get()); |
|
1276 } |
|
1277 |
|
1278 return NS_OK; |
|
1279 } |
|
1280 |
|
1281 FileTypeBox::FileTypeBox(ISOControl* aControl) |
|
1282 : Box(NS_LITERAL_CSTRING("ftyp"), aControl) |
|
1283 , minor_version(0) |
|
1284 { |
|
1285 MOZ_COUNT_CTOR(FileTypeBox); |
|
1286 } |
|
1287 |
|
1288 FileTypeBox::~FileTypeBox() |
|
1289 { |
|
1290 MOZ_COUNT_DTOR(FileTypeBox); |
|
1291 } |
|
1292 |
|
1293 MediaBox::MediaBox(uint32_t aType, ISOControl* aControl) |
|
1294 : DefaultContainerImpl(NS_LITERAL_CSTRING("mdia"), aControl) |
|
1295 { |
|
1296 mTrackType = aType; |
|
1297 boxes.AppendElement(new MediaHeaderBox(aType, aControl)); |
|
1298 boxes.AppendElement(new HandlerBox(aType, aControl)); |
|
1299 boxes.AppendElement(new MediaInformationBox(aType, aControl)); |
|
1300 MOZ_COUNT_CTOR(MediaBox); |
|
1301 } |
|
1302 |
|
1303 MediaBox::~MediaBox() |
|
1304 { |
|
1305 MOZ_COUNT_DTOR(MediaBox); |
|
1306 } |
|
1307 |
|
1308 nsresult |
|
1309 DefaultContainerImpl::Generate(uint32_t* aBoxSize) |
|
1310 { |
|
1311 nsresult rv; |
|
1312 uint32_t box_size; |
|
1313 uint32_t len = boxes.Length(); |
|
1314 for (uint32_t i = 0; i < len; i++) { |
|
1315 rv = boxes.ElementAt(i)->Generate(&box_size); |
|
1316 NS_ENSURE_SUCCESS(rv, rv); |
|
1317 size += box_size; |
|
1318 } |
|
1319 *aBoxSize = size; |
|
1320 return NS_OK; |
|
1321 } |
|
1322 |
|
1323 nsresult |
|
1324 DefaultContainerImpl::Find(const nsACString& aType, |
|
1325 nsTArray<nsRefPtr<MuxerOperation>>& aOperations) |
|
1326 { |
|
1327 nsresult rv = Box::Find(aType, aOperations); |
|
1328 NS_ENSURE_SUCCESS(rv, rv); |
|
1329 |
|
1330 uint32_t len = boxes.Length(); |
|
1331 for (uint32_t i = 0; i < len; i++) { |
|
1332 rv = boxes.ElementAt(i)->Find(aType, aOperations); |
|
1333 NS_ENSURE_SUCCESS(rv, rv); |
|
1334 } |
|
1335 return NS_OK; |
|
1336 } |
|
1337 |
|
1338 nsresult |
|
1339 DefaultContainerImpl::Write() |
|
1340 { |
|
1341 BoxSizeChecker checker(mControl, size); |
|
1342 Box::Write(); |
|
1343 |
|
1344 nsresult rv; |
|
1345 uint32_t len = boxes.Length(); |
|
1346 for (uint32_t i = 0; i < len; i++) { |
|
1347 rv = boxes.ElementAt(i)->Write(); |
|
1348 NS_ENSURE_SUCCESS(rv, rv); |
|
1349 } |
|
1350 |
|
1351 return NS_OK; |
|
1352 } |
|
1353 |
|
1354 DefaultContainerImpl::DefaultContainerImpl(const nsACString& aType, |
|
1355 ISOControl* aControl) |
|
1356 : Box(aType, aControl) |
|
1357 { |
|
1358 } |
|
1359 |
|
1360 nsresult |
|
1361 Box::Write() |
|
1362 { |
|
1363 mControl->Write(size); |
|
1364 mControl->WriteFourCC(boxType.get()); |
|
1365 return NS_OK; |
|
1366 } |
|
1367 |
|
1368 nsresult |
|
1369 Box::Find(const nsACString& aType, nsTArray<nsRefPtr<MuxerOperation>>& aOperations) |
|
1370 { |
|
1371 if (boxType == aType) { |
|
1372 aOperations.AppendElement(this); |
|
1373 } |
|
1374 return NS_OK; |
|
1375 } |
|
1376 |
|
1377 Box::Box(const nsACString& aType, ISOControl* aControl) |
|
1378 : size(8), mControl(aControl) |
|
1379 { |
|
1380 MOZ_ASSERT(aType.Length() == 4); |
|
1381 boxType = aType; |
|
1382 aControl->GetAudioMetadata(mAudioMeta); |
|
1383 aControl->GetVideoMetadata(mVideoMeta); |
|
1384 } |
|
1385 |
|
1386 FullBox::FullBox(const nsACString& aType, uint8_t aVersion, uint32_t aFlags, |
|
1387 ISOControl* aControl) |
|
1388 : Box(aType, aControl) |
|
1389 { |
|
1390 // Cast to uint64_t due to VC2010 bug. |
|
1391 std::bitset<24> tmp_flags((uint64_t)aFlags); |
|
1392 version = aVersion; |
|
1393 flags = tmp_flags; |
|
1394 size += sizeof(version) + flags.size() / CHAR_BIT; |
|
1395 } |
|
1396 |
|
1397 nsresult |
|
1398 FullBox::Write() |
|
1399 { |
|
1400 Box::Write(); |
|
1401 mControl->Write(version); |
|
1402 mControl->WriteBits(flags.to_ulong(), flags.size()); |
|
1403 return NS_OK; |
|
1404 } |
|
1405 |
|
1406 TrackBox::TrackBox(uint32_t aTrackType, ISOControl* aControl) |
|
1407 : DefaultContainerImpl(NS_LITERAL_CSTRING("trak"), aControl) |
|
1408 { |
|
1409 boxes.AppendElement(new TrackHeaderBox(aTrackType, aControl)); |
|
1410 boxes.AppendElement(new MediaBox(aTrackType, aControl)); |
|
1411 MOZ_COUNT_CTOR(TrackBox); |
|
1412 } |
|
1413 |
|
1414 TrackBox::~TrackBox() |
|
1415 { |
|
1416 MOZ_COUNT_DTOR(TrackBox); |
|
1417 } |
|
1418 |
|
1419 SampleEntryBox::SampleEntryBox(const nsACString& aFormat, ISOControl* aControl) |
|
1420 : Box(aFormat, aControl) |
|
1421 , data_reference_index(0) |
|
1422 { |
|
1423 data_reference_index = 1; // There is only one data reference in each track. |
|
1424 size += sizeof(reserved) + |
|
1425 sizeof(data_reference_index); |
|
1426 memset(reserved, 0, sizeof(reserved)); |
|
1427 } |
|
1428 |
|
1429 nsresult |
|
1430 SampleEntryBox::Write() |
|
1431 { |
|
1432 Box::Write(); |
|
1433 mControl->Write(reserved, sizeof(reserved)); |
|
1434 mControl->Write(data_reference_index); |
|
1435 return NS_OK; |
|
1436 } |
|
1437 |
|
1438 nsresult |
|
1439 AudioSampleEntry::Write() |
|
1440 { |
|
1441 SampleEntryBox::Write(); |
|
1442 mControl->Write(sound_version); |
|
1443 mControl->Write(reserved2, sizeof(reserved2)); |
|
1444 mControl->Write(channels); |
|
1445 mControl->Write(sample_size); |
|
1446 mControl->Write(compressionId); |
|
1447 mControl->Write(packet_size); |
|
1448 mControl->Write(timeScale); |
|
1449 return NS_OK; |
|
1450 } |
|
1451 |
|
1452 AudioSampleEntry::AudioSampleEntry(const nsACString& aFormat, ISOControl* aControl) |
|
1453 : SampleEntryBox(aFormat, aControl) |
|
1454 , sound_version(0) |
|
1455 , channels(2) |
|
1456 , sample_size(16) |
|
1457 , compressionId(0) |
|
1458 , packet_size(0) |
|
1459 , timeScale(0) |
|
1460 { |
|
1461 memset(reserved2, 0 , sizeof(reserved2)); |
|
1462 channels = mAudioMeta->GetAudioChannels(); |
|
1463 timeScale = mAudioMeta->GetAudioSampleRate() << 16; |
|
1464 |
|
1465 size += sizeof(sound_version) + |
|
1466 sizeof(reserved2) + |
|
1467 sizeof(sample_size) + |
|
1468 sizeof(channels) + |
|
1469 sizeof(packet_size) + |
|
1470 sizeof(compressionId) + |
|
1471 sizeof(timeScale); |
|
1472 |
|
1473 MOZ_COUNT_CTOR(AudioSampleEntry); |
|
1474 } |
|
1475 |
|
1476 AudioSampleEntry::~AudioSampleEntry() |
|
1477 { |
|
1478 MOZ_COUNT_DTOR(AudioSampleEntry); |
|
1479 } |
|
1480 |
|
1481 nsresult |
|
1482 VisualSampleEntry::Write() |
|
1483 { |
|
1484 SampleEntryBox::Write(); |
|
1485 |
|
1486 mControl->Write(reserved, sizeof(reserved)); |
|
1487 mControl->Write(width); |
|
1488 mControl->Write(height); |
|
1489 mControl->Write(horizresolution); |
|
1490 mControl->Write(vertresolution); |
|
1491 mControl->Write(reserved2); |
|
1492 mControl->Write(frame_count); |
|
1493 mControl->Write(compressorName, sizeof(compressorName)); |
|
1494 mControl->Write(depth); |
|
1495 mControl->Write(pre_defined); |
|
1496 |
|
1497 return NS_OK; |
|
1498 } |
|
1499 |
|
1500 VisualSampleEntry::VisualSampleEntry(const nsACString& aFormat, ISOControl* aControl) |
|
1501 : SampleEntryBox(aFormat, aControl) |
|
1502 , width(0) |
|
1503 , height(0) |
|
1504 , horizresolution(resolution_72_dpi) |
|
1505 , vertresolution(resolution_72_dpi) |
|
1506 , reserved2(0) |
|
1507 , frame_count(1) |
|
1508 , depth(video_depth) |
|
1509 , pre_defined(-1) |
|
1510 { |
|
1511 memset(reserved, 0 , sizeof(reserved)); |
|
1512 memset(compressorName, 0 , sizeof(compressorName)); |
|
1513 |
|
1514 // both fields occupy 16 bits defined in 14496-2 6.2.3. |
|
1515 width = mVideoMeta->GetVideoWidth(); |
|
1516 height = mVideoMeta->GetVideoHeight(); |
|
1517 |
|
1518 size += sizeof(reserved) + |
|
1519 sizeof(width) + |
|
1520 sizeof(height) + |
|
1521 sizeof(horizresolution) + |
|
1522 sizeof(vertresolution) + |
|
1523 sizeof(reserved2) + |
|
1524 sizeof(frame_count) + |
|
1525 sizeof(compressorName) + |
|
1526 sizeof(depth) + |
|
1527 sizeof(pre_defined); |
|
1528 |
|
1529 MOZ_COUNT_CTOR(VisualSampleEntry); |
|
1530 } |
|
1531 |
|
1532 VisualSampleEntry::~VisualSampleEntry() |
|
1533 { |
|
1534 MOZ_COUNT_DTOR(VisualSampleEntry); |
|
1535 } |
|
1536 |
|
1537 } |