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