1 /*******************************************************************************
2 mp4_writer.c - A library for writing MPEG4.
3
4 Copyright (C) 2007-2009 CodeShop B.V.
5 http://www.code-shop.com
6
7 For licensing see the LICENSE file
8 ******************************************************************************/
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #ifdef __cplusplus
15 #define __STDC_FORMAT_MACROS // C++ should define this for PRIu64
16 #define __STDC_LIMIT_MACROS // C++ should define this for UINT64_MAX
17 #endif
18
19 #include "mp4_writer.h"
20 #include "mp4_io.h"
21 #include <stdlib.h>
22 #include <string.h>
23
atom_writer_unknown(unknown_atom_t * atoms,unsigned char * buffer)24 static unsigned char* atom_writer_unknown(unknown_atom_t* atoms,
25 unsigned char* buffer)
26 {
27 while(atoms)
28 {
29 size_t size = read_32((const unsigned char*)atoms->atom_);
30 memcpy(buffer, atoms->atom_, size);
31 buffer += size;
32 atoms = atoms->next_;
33 }
34
35 return buffer;
36 }
37
atom_writer(struct unknown_atom_t * unknown_atoms,atom_write_list_t * atom_write_list,unsigned int atom_write_list_size,unsigned char * buffer)38 extern unsigned char* atom_writer(struct unknown_atom_t* unknown_atoms,
39 atom_write_list_t* atom_write_list,
40 unsigned int atom_write_list_size,
41 unsigned char* buffer)
42 {
43 unsigned i;
44 const int write_box64 = 0;
45
46 for(i = 0; i != atom_write_list_size; ++i)
47 {
48 if(atom_write_list[i].source_ != 0)
49 {
50 unsigned char* atom_start = buffer;
51 // atom size
52 if(write_box64)
53 {
54 write_32(buffer, 1); // box64
55 }
56 buffer += 4;
57
58 // atom type
59 buffer = write_32(buffer, atom_write_list[i].type_);
60 if(write_box64)
61 {
62 buffer += 8; // box64
63 }
64
65 // atom payload
66 buffer = atom_write_list[i].writer_(atom_write_list[i].source_, buffer);
67
68 if(write_box64)
69 write_64(atom_start + 8, buffer - atom_start);
70 else
71 write_32(atom_start, (uint32_t)(buffer - atom_start));
72 }
73 }
74
75 if(unknown_atoms)
76 {
77 buffer = atom_writer_unknown(unknown_atoms, buffer);
78 }
79
80 return buffer;
81 }
82
tkhd_write(void const * atom,unsigned char * buffer)83 static unsigned char* tkhd_write(void const* atom, unsigned char* buffer)
84 {
85 tkhd_t const* tkhd = (tkhd_t const*)atom;
86 unsigned int i;
87
88 buffer = write_8(buffer, tkhd->version_);
89 buffer = write_24(buffer, tkhd->flags_);
90
91 if(tkhd->version_ == 0)
92 {
93 buffer = write_32(buffer, (uint32_t)tkhd->creation_time_);
94 buffer = write_32(buffer, (uint32_t)tkhd->modification_time_);
95 buffer = write_32(buffer, tkhd->track_id_);
96 buffer = write_32(buffer, tkhd->reserved_);
97 buffer = write_32(buffer, (uint32_t)tkhd->duration_);
98 }
99 else
100 {
101 buffer = write_64(buffer, tkhd->creation_time_);
102 buffer = write_64(buffer, tkhd->modification_time_);
103 buffer = write_32(buffer, tkhd->track_id_);
104 buffer = write_32(buffer, tkhd->reserved_);
105 buffer = write_64(buffer, tkhd->duration_);
106 }
107
108 buffer = write_32(buffer, tkhd->reserved2_[0]);
109 buffer = write_32(buffer, tkhd->reserved2_[1]);
110 buffer = write_16(buffer, tkhd->layer_);
111 buffer = write_16(buffer, tkhd->predefined_);
112 buffer = write_16(buffer, tkhd->volume_);
113 buffer = write_16(buffer, tkhd->reserved3_);
114
115 for(i = 0; i != 9; ++i)
116 {
117 buffer = write_32(buffer, tkhd->matrix_[i]);
118 }
119
120 buffer = write_32(buffer, tkhd->width_);
121 buffer = write_32(buffer, tkhd->height_);
122
123 return buffer;
124 }
125
mdhd_write(void const * atom,unsigned char * buffer)126 static unsigned char* mdhd_write(void const* atom, unsigned char* buffer)
127 {
128 mdhd_t const* mdhd = (mdhd_t const*)atom;
129
130 buffer = write_8(buffer, mdhd->version_);
131 buffer = write_24(buffer, mdhd->flags_);
132
133 if(mdhd->version_ == 0)
134 {
135 buffer = write_32(buffer, (uint32_t)mdhd->creation_time_);
136 buffer = write_32(buffer, (uint32_t)mdhd->modification_time_);
137 buffer = write_32(buffer, mdhd->timescale_);
138 buffer = write_32(buffer, (uint32_t)mdhd->duration_);
139 }
140 else
141 {
142 buffer = write_64(buffer, mdhd->creation_time_);
143 buffer = write_64(buffer, mdhd->modification_time_);
144 buffer = write_32(buffer, mdhd->timescale_);
145 buffer = write_64(buffer, mdhd->duration_);
146 }
147
148 buffer = write_16(buffer,
149 ((mdhd->language_[0] - 0x60) << 10) +
150 ((mdhd->language_[1] - 0x60) << 5) +
151 ((mdhd->language_[2] - 0x60) << 0));
152
153 buffer = write_16(buffer, mdhd->predefined_);
154
155 return buffer;
156 }
157
vmhd_write(void const * atom,unsigned char * buffer)158 static unsigned char* vmhd_write(void const* atom, unsigned char* buffer)
159 {
160 vmhd_t const* vmhd = (vmhd_t const*)atom;
161 unsigned int i;
162
163 buffer = write_8(buffer, vmhd->version_);
164 buffer = write_24(buffer, vmhd->flags_);
165 buffer = write_16(buffer, vmhd->graphics_mode_);
166 for(i = 0; i != 3; ++i)
167 {
168 buffer = write_16(buffer, vmhd->opcolor_[i]);
169 }
170
171 return buffer;
172 }
173
smhd_write(void const * atom,unsigned char * buffer)174 static unsigned char* smhd_write(void const* atom, unsigned char* buffer)
175 {
176 smhd_t const* smhd = (smhd_t const*)atom;
177
178 buffer = write_8(buffer, smhd->version_);
179 buffer = write_24(buffer, smhd->flags_);
180
181 buffer = write_16(buffer, smhd->balance_);
182 buffer = write_16(buffer, smhd->reserved_);
183
184 return buffer;
185 }
186
dref_write(void const * atom,unsigned char * buffer)187 static unsigned char* dref_write(void const* atom, unsigned char* buffer)
188 {
189 unsigned int i;
190 dref_t const* dref = (dref_t const*)atom;
191
192 buffer = write_8(buffer, dref->version_);
193 buffer = write_24(buffer, dref->flags_);
194 buffer = write_32(buffer, dref->entry_count_);
195
196 for(i = 0; i != dref->entry_count_; ++i)
197 {
198 dref_table_t* entry = &dref->table_[i];
199 if(entry->flags_ == 0x000001)
200 {
201 write_32(buffer + 0, 12);
202 write_32(buffer + 4, FOURCC('u', 'r', 'l', ' '));
203 write_32(buffer + 8, entry->flags_);
204 buffer += 12;
205 }
206 else
207 {
208 // TODO: implement urn and url
209 }
210 }
211
212 return buffer;
213 }
214
dinf_write(void const * atom,unsigned char * buffer)215 static unsigned char* dinf_write(void const* atom, unsigned char* buffer)
216 {
217 dinf_t const* dinf = (dinf_t const*)atom;
218 atom_write_list_t atom_write_list[] = {
219 { FOURCC('d', 'r', 'e', 'f'), dinf->dref_, &dref_write },
220 };
221
222 buffer = atom_writer(NULL,
223 atom_write_list,
224 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
225 buffer);
226
227 return buffer;
228 }
229
hdlr_write(void const * atom,unsigned char * buffer)230 static unsigned char* hdlr_write(void const* atom, unsigned char* buffer)
231 {
232 hdlr_t const* hdlr = (hdlr_t const*)atom;
233 buffer = write_8(buffer, hdlr->version_);
234 buffer = write_24(buffer, hdlr->flags_);
235
236 buffer = write_32(buffer, hdlr->predefined_);
237 buffer = write_32(buffer, hdlr->handler_type_);
238 buffer = write_32(buffer, hdlr->reserved1_);
239 buffer = write_32(buffer, hdlr->reserved2_);
240 buffer = write_32(buffer, hdlr->reserved3_);
241 if(hdlr->name_)
242 {
243 char const* p;
244 if(hdlr->predefined_ == FOURCC('m', 'h', 'l', 'r'))
245 {
246 buffer = write_8(buffer, (unsigned int)(strlen(hdlr->name_)));
247 }
248
249 for(p = hdlr->name_; *p; ++p)
250 {
251 buffer = write_8(buffer, *p);
252 }
253 }
254
255 return buffer;
256 }
257
258 static unsigned char*
video_sample_entry_write(video_sample_entry_t const * sample_entry,unsigned char * buffer)259 video_sample_entry_write(video_sample_entry_t const* sample_entry,
260 unsigned char* buffer)
261 {
262 buffer = write_16(buffer, sample_entry->version_);
263 buffer = write_16(buffer, sample_entry->revision_level_);
264 buffer = write_32(buffer, sample_entry->vendor_);
265 buffer = write_32(buffer, sample_entry->temporal_quality_);
266 buffer = write_32(buffer, sample_entry->spatial_quality_);
267 buffer = write_16(buffer, sample_entry->width_);
268 buffer = write_16(buffer, sample_entry->height_);
269 buffer = write_32(buffer, sample_entry->horiz_resolution_);
270 buffer = write_32(buffer, sample_entry->vert_resolution_);
271 buffer = write_32(buffer, sample_entry->data_size_);
272 buffer = write_16(buffer, sample_entry->frame_count_);
273 memcpy(buffer, sample_entry->compressor_name_, 32);
274 buffer += 32;
275 buffer = write_16(buffer, sample_entry->depth_);
276 buffer = write_16(buffer, sample_entry->color_table_id_);
277
278 return buffer;
279 }
280
281 static unsigned char*
audio_sample_entry_write(audio_sample_entry_t const * sample_entry,unsigned char * buffer)282 audio_sample_entry_write(audio_sample_entry_t const* sample_entry,
283 unsigned char* buffer)
284 {
285 buffer = write_16(buffer, sample_entry->version_);
286 buffer = write_16(buffer, sample_entry->revision_);
287 buffer = write_32(buffer, sample_entry->vendor_);
288 buffer = write_16(buffer, sample_entry->channel_count_);
289 buffer = write_16(buffer, sample_entry->sample_size_);
290 buffer = write_16(buffer, sample_entry->compression_id_);
291 buffer = write_16(buffer, sample_entry->packet_size_);
292 buffer = write_32(buffer, sample_entry->samplerate_);
293
294 return buffer;
295 }
296
avcc_write(void const * atom,unsigned char * buffer)297 static unsigned char* avcc_write(void const* atom, unsigned char* buffer)
298 {
299 sample_entry_t const* sample_entry = (sample_entry_t const*)atom;
300
301 memcpy(buffer, sample_entry->codec_private_data_,
302 sample_entry->codec_private_data_length_);
303 buffer += sample_entry->codec_private_data_length_;
304
305 return buffer;
306 }
307
308 // returns the size of the descriptor including the tag and length
mp4_desc_len(uint32_t v)309 static unsigned int mp4_desc_len(uint32_t v)
310 {
311 unsigned int bytes = 0;
312
313 if(v >= 0x00200000)
314 ++bytes;
315 if(v >= 0x00004000)
316 ++bytes;
317 if(v >= 0x00000080)
318 ++bytes;
319 ++bytes;
320
321 return 1 + bytes + v;
322 }
323
mp4_write_desc_len(unsigned char * buffer,uint32_t v)324 static unsigned char* mp4_write_desc_len(unsigned char* buffer, uint32_t v)
325 {
326 if(v >= 0x00200000)
327 buffer = write_8(buffer, (v >> 21) | 0x80);
328 if(v >= 0x00004000)
329 buffer = write_8(buffer, (v >> 14) | 0x80);
330 if(v >= 0x00000080)
331 buffer = write_8(buffer, (v >> 7) | 0x80);
332
333 buffer = write_8(buffer, v & 0x7f);
334
335 return buffer;
336 }
337
338 // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
esds_write(void const * atom,unsigned char * buffer)339 static unsigned char* esds_write(void const* atom, unsigned char* buffer)
340 {
341 sample_entry_t const* sample_entry = (sample_entry_t const*)atom;
342
343 uint32_t decoder_specific_descriptor_length =
344 sample_entry->codec_private_data_length_ ?
345 mp4_desc_len(sample_entry->codec_private_data_length_) : 0;
346 uint32_t decoder_config_descriptor_length =
347 13 + decoder_specific_descriptor_length;
348 uint32_t elementary_stream_descriptor_length =
349 3 + mp4_desc_len(decoder_config_descriptor_length);
350
351 buffer = write_8(buffer, 0); // version
352 buffer = write_24(buffer, 0); // flags
353
354 buffer = write_8(buffer, MP4_ELEMENTARY_STREAM_DESCRIPTOR_TAG);
355 buffer = mp4_write_desc_len(buffer, elementary_stream_descriptor_length);
356 buffer = write_16(buffer, 1); // track_id
357 buffer = write_8(buffer, 0); // flags
358
359 buffer = write_8(buffer, MP4_DECODER_CONFIG_DESCRIPTOR_TAG);
360 buffer = mp4_write_desc_len(buffer, decoder_config_descriptor_length);
361
362 buffer = write_8(buffer, MP4_MPEG4Audio); // object_type_id
363 buffer = write_8(buffer, 0x15); // stream_type (0x11=vid, 0x15=aud)
364 buffer = write_24(buffer, 0); // buffer_size_db
365 buffer = write_32(buffer, 0); // max_bitrate
366 buffer = write_32(buffer, 0); // avg_bitrate
367
368 if(sample_entry->codec_private_data_length_)
369 {
370 buffer = write_8(buffer, MP4_DECODER_SPECIFIC_DESCRIPTOR_TAG);
371 buffer = mp4_write_desc_len(buffer,
372 sample_entry->codec_private_data_length_);
373 memcpy(buffer, sample_entry->codec_private_data_,
374 sample_entry->codec_private_data_length_);
375 buffer += sample_entry->codec_private_data_length_;
376 }
377
378 buffer = write_8(buffer, 6); // SL
379 buffer = mp4_write_desc_len(buffer, 1);
380 buffer = write_8(buffer, 0x02);
381
382 return buffer;
383 }
384
stsd_write(void const * atom,unsigned char * buffer)385 static unsigned char* stsd_write(void const* atom, unsigned char* buffer)
386 {
387 stsd_t const* stsd = (stsd_t const*)atom;
388 unsigned int i;
389
390 buffer = write_8(buffer, stsd->version_);
391 buffer = write_24(buffer, stsd->flags_);
392 buffer = write_32(buffer, stsd->entries_);
393 for(i = 0; i != stsd->entries_; ++i)
394 {
395 sample_entry_t const* sample_entry = &stsd->sample_entries_[i];
396 unsigned int j = 0;
397 if(sample_entry->buf_ != NULL)
398 {
399 // just copy the sample_entry as we read it
400 buffer = write_32(buffer, sample_entry->len_ + 8);
401 buffer = write_32(buffer, sample_entry->fourcc_);
402 for(j = 0; j != sample_entry->len_; ++j)
403 {
404 buffer = write_8(buffer, sample_entry->buf_[j]);
405 }
406 }
407 else
408 {
409 unsigned char* sample_entry_buffer = buffer;
410 buffer = write_32(buffer, 0);
411 buffer = write_32(buffer, sample_entry->fourcc_);
412
413 buffer = write_32(buffer, 0); // 6 bytes reserved
414 buffer = write_16(buffer, 0);
415 buffer = write_16(buffer, 1); // data reference index
416
417 if(sample_entry->video_)
418 {
419 atom_write_list_t atom_write_list[] = {
420 { FOURCC('a', 'v', 'c', 'C'), sample_entry, &avcc_write },
421 };
422
423 buffer = video_sample_entry_write(sample_entry->video_, buffer);
424
425 buffer = atom_writer(NULL,
426 atom_write_list,
427 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
428 buffer);
429 }
430 else if(sample_entry->audio_)
431 {
432 atom_write_list_t atom_write_list[] = {
433 { FOURCC('e', 's', 'd', 's'), sample_entry, &esds_write },
434 };
435
436 buffer = audio_sample_entry_write(sample_entry->audio_, buffer);
437
438 buffer = atom_writer(NULL,
439 atom_write_list,
440 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
441 buffer);
442 }
443 write_32(sample_entry_buffer, buffer - sample_entry_buffer);
444 }
445 }
446
447 return buffer;
448 }
449
stts_write(void const * atom,unsigned char * buffer)450 static unsigned char* stts_write(void const* atom, unsigned char* buffer)
451 {
452 stts_t const* stts = (stts_t const*)atom;
453 unsigned int i;
454
455 buffer = write_8(buffer, stts->version_);
456 buffer = write_24(buffer, stts->flags_);
457 buffer = write_32(buffer, stts->entries_);
458 for(i = 0; i != stts->entries_; ++i)
459 {
460 buffer = write_32(buffer, stts->table_[i].sample_count_);
461 buffer = write_32(buffer, stts->table_[i].sample_duration_);
462 }
463
464 return buffer;
465 }
466
stss_write(void const * atom,unsigned char * buffer)467 static unsigned char* stss_write(void const* atom, unsigned char* buffer)
468 {
469 stss_t const* stss = (stss_t const*)atom;
470 unsigned int i;
471
472 buffer = write_8(buffer, stss->version_);
473 buffer = write_24(buffer, stss->flags_);
474 buffer = write_32(buffer, stss->entries_);
475 for(i = 0; i != stss->entries_; ++i)
476 {
477 buffer = write_32(buffer, stss->sample_numbers_[i]);
478 }
479
480 return buffer;
481 }
482
stsc_write(void const * atom,unsigned char * buffer)483 static unsigned char* stsc_write(void const* atom, unsigned char* buffer)
484 {
485 stsc_t const* stsc = (stsc_t const*)atom;
486 unsigned int i;
487
488 buffer = write_8(buffer, stsc->version_);
489 buffer = write_24(buffer, stsc->flags_);
490 buffer = write_32(buffer, stsc->entries_);
491 for(i = 0; i != stsc->entries_; ++i)
492 {
493 buffer = write_32(buffer, stsc->table_[i].chunk_ + 1);
494 buffer = write_32(buffer, stsc->table_[i].samples_);
495 buffer = write_32(buffer, stsc->table_[i].id_);
496 }
497
498 return buffer;
499 }
500
stsz_write(void const * atom,unsigned char * buffer)501 static unsigned char* stsz_write(void const* atom, unsigned char* buffer)
502 {
503 stsz_t const* stsz = (stsz_t const*)atom;
504 unsigned int i;
505
506 buffer = write_8(buffer, stsz->version_);
507 buffer = write_24(buffer, stsz->flags_);
508 buffer = write_32(buffer, stsz->sample_size_);
509 buffer = write_32(buffer, stsz->entries_);
510 if(!stsz->sample_size_)
511 {
512 for(i = 0; i != stsz->entries_; ++i)
513 {
514 buffer = write_32(buffer, stsz->sample_sizes_[i]);
515 }
516 }
517
518 return buffer;
519 }
520
stco_write(void const * atom,unsigned char * buffer)521 static unsigned char* stco_write(void const* atom, unsigned char* buffer)
522 {
523 stco_t const* stco = (stco_t const*)atom;
524 unsigned int i;
525
526 // newly generated stco (patched inplace)
527 ((stco_t*)stco)->stco_inplace_ = buffer;
528
529 buffer = write_8(buffer, stco->version_);
530 buffer = write_24(buffer, stco->flags_);
531 buffer = write_32(buffer, stco->entries_);
532 for(i = 0; i != stco->entries_; ++i)
533 {
534 buffer = write_32(buffer, (uint32_t)(stco->chunk_offsets_[i]));
535 }
536
537 return buffer;
538 }
539
ctts_write(void const * atom,unsigned char * buffer)540 static unsigned char* ctts_write(void const* atom, unsigned char* buffer)
541 {
542 ctts_t const* ctts = (ctts_t const*)atom;
543 unsigned int i;
544
545 buffer = write_8(buffer, ctts->version_);
546 buffer = write_24(buffer, ctts->flags_);
547 buffer = write_32(buffer, ctts->entries_);
548 for(i = 0; i != ctts->entries_; ++i)
549 {
550 buffer = write_32(buffer, (uint32_t)(ctts->table_[i].sample_count_));
551 buffer = write_32(buffer, (uint32_t)(ctts->table_[i].sample_offset_));
552 }
553
554 return buffer;
555 }
556
stbl_write(void const * atom,unsigned char * buffer)557 static unsigned char* stbl_write(void const* atom, unsigned char* buffer)
558 {
559 stbl_t const* stbl = (stbl_t const*)atom;
560 atom_write_list_t atom_write_list[] = {
561 { FOURCC('s', 't', 's', 'd'), stbl->stsd_, &stsd_write },
562 { FOURCC('s', 't', 't', 's'), stbl->stts_, &stts_write },
563 { FOURCC('c', 't', 't', 's'), stbl->ctts_, &ctts_write },
564 { FOURCC('s', 't', 's', 'c'), stbl->stsc_, &stsc_write },
565 { FOURCC('s', 't', 's', 'z'), stbl->stsz_, &stsz_write },
566 { FOURCC('s', 't', 'c', 'o'), stbl->stco_, &stco_write },
567 { FOURCC('s', 't', 's', 's'), stbl->stss_, &stss_write },
568 };
569
570 buffer = atom_writer(stbl->unknown_atoms_,
571 atom_write_list,
572 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
573 buffer);
574
575 return buffer;
576 }
577
minf_write(void const * atom,unsigned char * buffer)578 static unsigned char* minf_write(void const* atom, unsigned char* buffer)
579 {
580 minf_t const* minf = (minf_t const*)atom;
581 atom_write_list_t atom_write_list[] = {
582 { FOURCC('v', 'm', 'h', 'd'), minf->vmhd_, &vmhd_write },
583 { FOURCC('s', 'm', 'h', 'd'), minf->smhd_, &smhd_write },
584 { FOURCC('d', 'i', 'n', 'f'), minf->dinf_, &dinf_write },
585 { FOURCC('s', 't', 'b', 'l'), minf->stbl_, &stbl_write }
586 };
587
588 buffer = atom_writer(minf->unknown_atoms_,
589 atom_write_list,
590 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
591 buffer);
592
593 return buffer;
594 }
595
mdia_write(void const * atom,unsigned char * buffer)596 static unsigned char* mdia_write(void const* atom, unsigned char* buffer)
597 {
598 mdia_t const* mdia = (mdia_t const*)atom;
599 atom_write_list_t atom_write_list[] = {
600 { FOURCC('m', 'd', 'h', 'd'), mdia->mdhd_, &mdhd_write },
601 { FOURCC('h', 'd', 'l', 'r'), mdia->hdlr_, &hdlr_write },
602 { FOURCC('m', 'i', 'n', 'f'), mdia->minf_, &minf_write }
603 };
604
605 buffer = atom_writer(mdia->unknown_atoms_,
606 atom_write_list,
607 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
608 buffer);
609
610 return buffer;
611 }
612
elst_write(void const * atom,unsigned char * buffer)613 static unsigned char* elst_write(void const* atom, unsigned char* buffer)
614 {
615 elst_t const* elst = (elst_t const*)atom;
616 unsigned int i;
617
618 buffer = write_8(buffer, elst->version_);
619 buffer = write_24(buffer, elst->flags_);
620 buffer = write_32(buffer, elst->entry_count_);
621 for(i = 0; i != elst->entry_count_; ++i)
622 {
623 if(elst->version_ == 0)
624 {
625 buffer = write_32(buffer, (uint32_t)(elst->table_[i].segment_duration_));
626 buffer = write_32(buffer, (uint32_t)(elst->table_[i].media_time_));
627 }
628 else
629 {
630 buffer = write_64(buffer, elst->table_[i].segment_duration_);
631 buffer = write_64(buffer, elst->table_[i].media_time_);
632 }
633 buffer = write_16(buffer, elst->table_[i].media_rate_integer_);
634 buffer = write_16(buffer, elst->table_[i].media_rate_fraction_);
635 }
636
637 return buffer;
638 }
639
edts_write(void const * atom,unsigned char * buffer)640 static unsigned char* edts_write(void const* atom, unsigned char* buffer)
641 {
642 edts_t const* edts = (edts_t const*)atom;
643 atom_write_list_t atom_write_list[] = {
644 { FOURCC('e', 'l', 's', 't'), edts->elst_, &elst_write }
645 };
646
647 buffer = atom_writer(edts->unknown_atoms_,
648 atom_write_list,
649 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
650 buffer);
651
652 return buffer;
653 }
654
trak_write(void const * atom,unsigned char * buffer)655 static unsigned char* trak_write(void const* atom, unsigned char* buffer)
656 {
657 trak_t const* trak = (trak_t const*)atom;
658 atom_write_list_t atom_write_list[] = {
659 { FOURCC('t', 'k', 'h', 'd'), trak->tkhd_, &tkhd_write },
660 { FOURCC('m', 'd', 'i', 'a'), trak->mdia_, &mdia_write },
661 { FOURCC('e', 'd', 't', 's'), trak->edts_, &edts_write }
662 };
663
664 buffer = atom_writer(trak->unknown_atoms_,
665 atom_write_list,
666 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
667 buffer);
668
669 return buffer;
670 }
671
mvhd_write(void const * atom,unsigned char * buffer)672 static unsigned char* mvhd_write(void const* atom, unsigned char* buffer)
673 {
674 mvhd_t const* mvhd = (mvhd_t const*)atom;
675 unsigned int i;
676
677 buffer = write_8(buffer, mvhd->version_);
678 buffer = write_24(buffer, mvhd->flags_);
679
680 if(mvhd->version_ == 0)
681 {
682 buffer = write_32(buffer, (uint32_t)mvhd->creation_time_);
683 buffer = write_32(buffer, (uint32_t)mvhd->modification_time_);
684 buffer = write_32(buffer, mvhd->timescale_);
685 buffer = write_32(buffer, (uint32_t)mvhd->duration_);
686 }
687 else
688 {
689 buffer = write_64(buffer, mvhd->creation_time_);
690 buffer = write_64(buffer, mvhd->modification_time_);
691 buffer = write_32(buffer, mvhd->timescale_);
692 buffer = write_64(buffer, mvhd->duration_);
693 }
694
695 buffer = write_32(buffer, mvhd->rate_);
696 buffer = write_16(buffer, mvhd->volume_);
697 buffer = write_16(buffer, mvhd->reserved1_);
698 buffer = write_32(buffer, mvhd->reserved2_[0]);
699 buffer = write_32(buffer, mvhd->reserved2_[1]);
700
701 for(i = 0; i != 9; ++i)
702 {
703 buffer = write_32(buffer, mvhd->matrix_[i]);
704 }
705
706 for(i = 0; i != 6; ++i)
707 {
708 buffer = write_32(buffer, mvhd->predefined_[i]);
709 }
710
711 buffer = write_32(buffer, mvhd->next_track_id_);
712
713 return buffer;
714 }
715
trex_write(void const * atom,unsigned char * buffer)716 static unsigned char* trex_write(void const* atom, unsigned char* buffer)
717 {
718 trex_t const* trex = (trex_t const*)atom;
719
720 buffer = write_8(buffer, trex->version_);
721 buffer = write_24(buffer, trex->flags_);
722
723 buffer = write_32(buffer, trex->track_id_);
724 buffer = write_32(buffer, trex->default_sample_description_index_);
725 buffer = write_32(buffer, trex->default_sample_duration_);
726 buffer = write_32(buffer, trex->default_sample_size_);
727 buffer = write_32(buffer, trex->default_sample_flags_);
728
729 return buffer;
730 }
731
mvex_write(void const * atom,unsigned char * buffer)732 static unsigned char* mvex_write(void const* atom, unsigned char* buffer)
733 {
734 mvex_t const* mvex = (mvex_t const*)atom;
735
736 unsigned i;
737
738 buffer = atom_writer(mvex->unknown_atoms_, NULL, 0, buffer);
739
740 for(i = 0; i != mvex->tracks_; ++i)
741 {
742 atom_write_list_t mvex_atom_write_list[] = {
743 // { FOURCC('m', 'e', 'h', 'd'), NULL, NULL },
744 { FOURCC('t', 'r', 'e', 'x'), mvex->trexs_[i], &trex_write },
745 };
746 buffer = atom_writer(0,
747 mvex_atom_write_list,
748 sizeof(mvex_atom_write_list) / sizeof(mvex_atom_write_list[0]),
749 buffer);
750 }
751
752 return buffer;
753 }
754
moov_write(moov_t * atom,unsigned char * buffer)755 extern uint32_t moov_write(moov_t* atom, unsigned char* buffer)
756 {
757 unsigned i;
758
759 unsigned char* atom_start = buffer;
760
761 atom_write_list_t atom_write_list[] = {
762 { FOURCC('m', 'v', 'h', 'd'), atom->mvhd_, &mvhd_write },
763 { FOURCC('m', 'v', 'e', 'x'), atom->mvex_, &mvex_write }
764 };
765
766 // atom size
767 buffer += 4;
768
769 // atom type
770 buffer = write_32(buffer, FOURCC('m', 'o', 'o', 'v'));
771
772 buffer = atom_writer(atom->unknown_atoms_,
773 atom_write_list,
774 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
775 buffer);
776
777 for(i = 0; i != atom->tracks_; ++i)
778 {
779 atom_write_list_t trak_atom_write_list[] = {
780 { FOURCC('t', 'r', 'a', 'k'), atom->traks_[i], &trak_write },
781 };
782 buffer = atom_writer(0,
783 trak_atom_write_list,
784 sizeof(trak_atom_write_list) / sizeof(trak_atom_write_list[0]),
785 buffer);
786 }
787
788 write_32(atom_start, (uint32_t)(buffer - atom_start));
789
790 return buffer - atom_start;
791 }
792
tfra_write(void const * atom,unsigned char * buffer)793 static unsigned char* tfra_write(void const* atom, unsigned char* buffer)
794 {
795 tfra_t const* tfra = (tfra_t const*)atom;
796 unsigned int i;
797 uint32_t length_fields;
798
799 buffer = write_8(buffer, tfra->version_);
800 buffer = write_24(buffer, tfra->flags_);
801
802 buffer = write_32(buffer, tfra->track_id_);
803 length_fields = ((tfra->length_size_of_traf_num_ - 1) << 4) +
804 ((tfra->length_size_of_trun_num_ - 1) << 2) +
805 ((tfra->length_size_of_sample_num_ - 1) << 0);
806 buffer = write_32(buffer, length_fields);
807
808 buffer = write_32(buffer, tfra->number_of_entry_);
809 for(i = 0; i != tfra->number_of_entry_; ++i)
810 {
811 tfra_table_t* table = &tfra->table_[i];
812 if(tfra->version_ == 0)
813 {
814 buffer = write_32(buffer, (uint32_t)table->time_);
815 buffer = write_32(buffer, (uint32_t)table->moof_offset_);
816 }
817 else
818 {
819 buffer = write_64(buffer, table->time_);
820 buffer = write_64(buffer, table->moof_offset_);
821 }
822
823 buffer = write_n(buffer, tfra->length_size_of_traf_num_ * 8,
824 table->traf_number_ + 1);
825 buffer = write_n(buffer, tfra->length_size_of_trun_num_ * 8,
826 table->trun_number_ + 1);
827 buffer = write_n(buffer, tfra->length_size_of_sample_num_ * 8,
828 table->sample_number_ + 1);
829 }
830
831 return buffer;
832 }
833
mfra_write(mfra_t const * mfra,unsigned char * buffer)834 extern uint32_t mfra_write(mfra_t const* mfra, unsigned char* buffer)
835 {
836 unsigned i;
837
838 unsigned char* atom_start = buffer;
839 uint32_t atom_size;
840
841 // atom size
842 buffer += 4;
843
844 // atom type
845 buffer = write_32(buffer, FOURCC('m', 'f', 'r', 'a'));
846
847 buffer = atom_writer(mfra->unknown_atoms_, NULL, 0, buffer);
848
849 for(i = 0; i != mfra->tracks_; ++i)
850 {
851 atom_write_list_t mfra_atom_write_list[] = {
852 { FOURCC('t', 'f', 'r', 'a'), mfra->tfras_[i], &tfra_write },
853 };
854 buffer = atom_writer(0,
855 mfra_atom_write_list,
856 sizeof(mfra_atom_write_list) / sizeof(mfra_atom_write_list[0]),
857 buffer);
858 }
859
860 // write Movie Fragment Random Access Offset Box (mfro)
861 {
862 buffer = write_32(buffer, 16);
863 buffer = write_32(buffer, FOURCC('m', 'f', 'r', 'o'));
864 buffer = write_32(buffer, 0);
865 buffer = write_32(buffer, (uint32_t)(buffer - atom_start + 4));
866 }
867
868 atom_size = (uint32_t)(buffer - atom_start);
869 write_32(atom_start, atom_size);
870
871 return atom_size;
872 }
873
tfhd_write(void const * atom,unsigned char * buffer)874 static unsigned char* tfhd_write(void const* atom, unsigned char* buffer)
875 {
876 struct tfhd_t const* tfhd = (struct tfhd_t const*)atom;
877
878 buffer = write_8(buffer, tfhd->version_);
879 buffer = write_24(buffer, tfhd->flags_);
880
881 buffer = write_32(buffer, tfhd->track_id_);
882
883 if(tfhd->flags_ & 0x000001)
884 {
885 buffer = write_64(buffer, tfhd->base_data_offset_);
886 }
887 if(tfhd->flags_ & 0x000002)
888 {
889 buffer = write_32(buffer, tfhd->sample_description_index_);
890 }
891 if(tfhd->flags_ & 0x000008)
892 {
893 buffer = write_32(buffer, tfhd->default_sample_duration_);
894 }
895 if(tfhd->flags_ & 0x000010)
896 {
897 buffer = write_32(buffer, tfhd->default_sample_size_);
898 }
899 if(tfhd->flags_ & 0x000020)
900 {
901 buffer = write_32(buffer, tfhd->default_sample_flags_);
902 }
903
904 return buffer;
905 }
906
trun_write(void const * atom,unsigned char * buffer)907 static unsigned char* trun_write(void const* atom, unsigned char* buffer)
908 {
909 // TODO: add writing of multiple truns (we can't do that here, as we need to
910 // write an atom header for each trun)
911 trun_t const* trun = (trun_t const*)atom;
912 unsigned int i;
913
914 buffer = write_8(buffer, trun->version_);
915 buffer = write_24(buffer, trun->flags_);
916
917 buffer = write_32(buffer, trun->sample_count_);
918
919 // data offset
920 if(trun->flags_ & 0x0001)
921 {
922 buffer = write_32(buffer, trun->data_offset_);
923 }
924 // first sample flag
925 if(trun->flags_ & 0x0004)
926 {
927 buffer = write_32(buffer, trun->first_sample_flags_);
928 }
929
930 for(i = 0; i != trun->sample_count_; ++i)
931 {
932 if(trun->flags_ & 0x0100)
933 {
934 buffer = write_32(buffer, trun->table_[i].sample_duration_);
935 }
936 if(trun->flags_ & 0x0200)
937 {
938 buffer = write_32(buffer, trun->table_[i].sample_size_);
939 }
940 if(trun->flags_ & 0x0800)
941 {
942 buffer = write_32(buffer, trun->table_[i].sample_composition_time_offset_);
943 }
944 }
945
946 return buffer;
947 }
948
uuid0_write(void const * atom,unsigned char * buffer)949 static unsigned char* uuid0_write(void const* atom, unsigned char* buffer)
950 {
951 uuid0_t const* uuid = (uuid0_t const*)atom;
952
953 static const unsigned char uuid0[] = {
954 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
955 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
956 };
957
958 memcpy(buffer, uuid0, sizeof(uuid0));
959 buffer += sizeof(uuid0);
960
961 buffer = write_8(buffer, 0x01);
962 buffer = write_24(buffer, 0x00);
963 buffer = write_64(buffer, uuid->pts_);
964 buffer = write_64(buffer, uuid->duration_);
965
966 return buffer;
967 }
968
uuid1_write(void const * atom,unsigned char * buffer)969 static unsigned char* uuid1_write(void const* atom, unsigned char* buffer)
970 {
971 uuid1_t const* uuid = (uuid1_t const*)atom;
972
973 static const unsigned char uuid1[] = {
974 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
975 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
976 };
977 unsigned int i;
978
979 memcpy(buffer, uuid1, sizeof(uuid1));
980 buffer += sizeof(uuid1);
981
982 buffer = write_8(buffer, 0x01);
983 buffer = write_24(buffer, 0x00);
984
985 buffer = write_8(buffer, uuid->entries_);
986 for(i = 0; i != uuid->entries_; ++i)
987 {
988 buffer = write_64(buffer, uuid->pts_[i]);
989 buffer = write_64(buffer, uuid->duration_[i]);
990 }
991
992 #if 0
993 // 0x485482a4d55 = 497048.7893333 = 138:04:08.7893333
994 // 0x485498ebf55 = 497051.1253333 = 138:04:11.1253333
995 // 0x1647200 = 2.3360000
996 // 0x1339e00 = 2.0160000
997
998 buffer = write_64(buffer, 0x00000485482a4d55);
999 buffer = write_64(buffer, 0x1647200); // next duration?
1000
1001 buffer = write_64(buffer, 0x00000485498ebf55);
1002 buffer = write_64(buffer, 0x1339e00); // next next duration?
1003 #endif
1004
1005 return buffer;
1006 }
1007
mfhd_write(void const * atom,unsigned char * buffer)1008 static unsigned char* mfhd_write(void const* atom, unsigned char* buffer)
1009 {
1010 mfhd_t const* mfhd = (mfhd_t const*)atom;
1011
1012 buffer = write_8(buffer, mfhd->version_);
1013 buffer = write_24(buffer, mfhd->flags_);
1014
1015 buffer = write_32(buffer, mfhd->sequence_number_);
1016
1017 return buffer;
1018 }
1019
traf_write(void const * atom,unsigned char * buffer)1020 static unsigned char* traf_write(void const* atom, unsigned char* buffer)
1021 {
1022 traf_t const* traf = (traf_t const*)atom;
1023 atom_write_list_t atom_write_list[] = {
1024 { FOURCC('t', 'f', 'h', 'd'), traf->tfhd_, &tfhd_write },
1025 { FOURCC('t', 'r', 'u', 'n'), traf->trun_, &trun_write },
1026 #if 1 // defined(HACK_LIVE_SMOOTH_STREAMING)
1027 { FOURCC('u', 'u', 'i', 'd'), traf->uuid0_, &uuid0_write },
1028 { FOURCC('u', 'u', 'i', 'd'), traf->uuid1_, &uuid1_write }
1029 #endif
1030 };
1031
1032 buffer = atom_writer(traf->unknown_atoms_,
1033 atom_write_list,
1034 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
1035 buffer);
1036
1037 return buffer;
1038 }
1039
moof_write(struct moof_t * atom,unsigned char * buffer)1040 extern uint32_t moof_write(struct moof_t* atom, unsigned char* buffer)
1041 {
1042 unsigned i;
1043
1044 unsigned char* atom_start = buffer;
1045
1046 atom_write_list_t atom_write_list[] = {
1047 { FOURCC('m', 'f', 'h', 'd'), atom->mfhd_, &mfhd_write },
1048 };
1049
1050 // atom size
1051 buffer += 4;
1052
1053 // atom type
1054 buffer = write_32(buffer, FOURCC('m', 'o', 'o', 'f'));
1055
1056 buffer = atom_writer(atom->unknown_atoms_,
1057 atom_write_list,
1058 sizeof(atom_write_list) / sizeof(atom_write_list[0]),
1059 buffer);
1060
1061 for(i = 0; i != atom->tracks_; ++i)
1062 {
1063 atom_write_list_t traf_atom_write_list[] = {
1064 { FOURCC('t', 'r', 'a', 'f'), atom->trafs_[i], &traf_write },
1065 };
1066 buffer = atom_writer(0,
1067 traf_atom_write_list,
1068 sizeof(traf_atom_write_list) / sizeof(traf_atom_write_list[0]),
1069 buffer);
1070 }
1071 write_32(atom_start, (uint32_t)(buffer - atom_start));
1072
1073 return buffer - atom_start;
1074 }
1075
1076 // End Of File
1077
1078