| |
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 } |