636f21c2955b2e4469eb5abe3dd11c1ab0aff045
[platform/upstream/gst-plugins-good.git] / gst / quicktime / atoms.c
1 /* Quicktime muxer plugin for GStreamer
2  * Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
3  * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "atoms.h"
22 #include <string.h>
23 #include <glib.h>
24
25 /* only needed for gst_util_uint64_scale */
26 #include <gst/gst.h>
27
28 /**
29  * Creates a new AtomsContext for the given flavor.
30  */
31 AtomsContext *
32 atoms_context_new (AtomsTreeFlavor flavor)
33 {
34   AtomsContext *context = g_new0 (AtomsContext, 1);
35   context->flavor = flavor;
36   return context;
37 }
38
39 /**
40  * Frees an AtomsContext and all memory associated with it
41  */
42 void
43 atoms_context_free (AtomsContext * context)
44 {
45   g_free (context);
46 }
47
48 /* -- creation, initialization, clear and free functions -- */
49
50 #define SECS_PER_DAY (24 * 60 * 60)
51 #define LEAP_YEARS_FROM_1904_TO_1970 17
52
53 static guint64
54 get_current_qt_time ()
55 {
56   GTimeVal timeval;
57
58   g_get_current_time (&timeval);
59   /* FIXME this should use UTC coordinated time */
60   return timeval.tv_sec + (((1970 - 1904) * (guint64) 365) +
61       LEAP_YEARS_FROM_1904_TO_1970) * SECS_PER_DAY;
62 }
63
64 static void
65 common_time_info_init (TimeInfo * ti)
66 {
67   ti->creation_time = ti->modification_time = get_current_qt_time ();
68   ti->timescale = 0;
69   ti->duration = 0;
70 }
71
72 static void
73 atom_header_set (Atom * header, guint32 fourcc, gint32 size, gint64 ext_size)
74 {
75   header->type = fourcc;
76   header->size = size;
77   header->extended_size = ext_size;
78 }
79
80 static void
81 atom_clear (Atom * atom)
82 {
83 }
84
85 static void
86 atom_full_init (AtomFull * full, guint32 fourcc, gint32 size, gint64 ext_size,
87     guint8 version, guint8 flags[3])
88 {
89   atom_header_set (&(full->header), fourcc, size, ext_size);
90   full->version = version;
91   full->flags[0] = flags[0];
92   full->flags[1] = flags[1];
93   full->flags[2] = flags[2];
94 }
95
96 static void
97 atom_full_clear (AtomFull * full)
98 {
99   atom_clear (&full->header);
100 }
101
102 static void
103 atom_full_free (AtomFull * full)
104 {
105   atom_full_clear (full);
106   g_free (full);
107 }
108
109 static AtomInfo *
110 build_atom_info_wrapper (Atom * atom, gpointer copy_func, gpointer free_func)
111 {
112   AtomInfo *info = NULL;
113
114   if (atom) {
115     info = g_new0 (AtomInfo, 1);
116
117     info->atom = atom;
118     info->copy_data_func = copy_func;
119     info->free_func = free_func;
120   }
121
122   return info;
123 }
124
125 static GList *
126 atom_info_list_prepend_atom (GList * ai, Atom * atom,
127     AtomCopyDataFunc copy_func, AtomFreeFunc free_func)
128 {
129   if (atom)
130     return g_list_prepend (ai,
131         build_atom_info_wrapper (atom, copy_func, free_func));
132   else
133     return ai;
134 }
135
136 static void
137 atom_info_list_free (GList * ai)
138 {
139   while (ai) {
140     AtomInfo *info = (AtomInfo *) ai->data;
141
142     info->free_func (info->atom);
143     g_free (info);
144     ai = g_list_delete_link (ai, ai);
145   }
146 }
147
148 static AtomData *
149 atom_data_new (guint32 fourcc)
150 {
151   AtomData *data = g_new0 (AtomData, 1);
152
153   atom_header_set (&data->header, fourcc, 0, 0);
154   return data;
155 }
156
157 static void
158 atom_data_alloc_mem (AtomData * data, guint32 size)
159 {
160   if (data->data) {
161     g_free (data->data);
162   }
163   data->data = g_new0 (guint8, size);
164   data->datalen = size;
165 }
166
167 static AtomData *
168 atom_data_new_from_gst_buffer (guint32 fourcc, const GstBuffer * buf)
169 {
170   AtomData *data = atom_data_new (fourcc);
171
172   atom_data_alloc_mem (data, GST_BUFFER_SIZE (buf));
173   g_memmove (data->data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
174   return data;
175 }
176
177 static void
178 atom_data_free (AtomData * data)
179 {
180   atom_clear (&data->header);
181   g_free (data->data);
182   g_free (data);
183 }
184
185 static void
186 atom_ftyp_init (AtomFTYP * ftyp, guint32 major, guint32 version, GList * brands)
187 {
188   gint index;
189   GList *it = NULL;
190
191   atom_header_set (&ftyp->header, FOURCC_ftyp, 16, 0);
192   ftyp->major_brand = major;
193   ftyp->version = version;
194
195   /* always include major brand as compatible brand */
196   ftyp->compatible_brands_size = g_list_length (brands) + 1;
197   ftyp->compatible_brands = g_new (guint32, ftyp->compatible_brands_size);
198
199   ftyp->compatible_brands[0] = major;
200   index = 1;
201   for (it = brands; it != NULL; it = g_list_next (it)) {
202     ftyp->compatible_brands[index++] = GPOINTER_TO_UINT (it->data);
203   }
204 }
205
206 AtomFTYP *
207 atom_ftyp_new (AtomsContext * context, guint32 major, guint32 version,
208     GList * brands)
209 {
210   AtomFTYP *ftyp = g_new0 (AtomFTYP, 1);
211
212   atom_ftyp_init (ftyp, major, version, brands);
213   return ftyp;
214 }
215
216 void
217 atom_ftyp_free (AtomFTYP * ftyp)
218 {
219   atom_clear (&ftyp->header);
220   g_free (ftyp->compatible_brands);
221   ftyp->compatible_brands = NULL;
222   g_free (ftyp);
223 }
224
225 static void
226 atom_esds_init (AtomESDS * esds)
227 {
228   guint8 flags[3] = { 0, 0, 0 };
229
230   atom_full_init (&esds->header, FOURCC_esds, 0, 0, 0, flags);
231   desc_es_init (&esds->es);
232 }
233
234 static AtomESDS *
235 atom_esds_new ()
236 {
237   AtomESDS *esds = g_new0 (AtomESDS, 1);
238
239   atom_esds_init (esds);
240   return esds;
241 }
242
243 static void
244 atom_esds_free (AtomESDS * esds)
245 {
246   atom_full_clear (&esds->header);
247   desc_es_descriptor_clear (&esds->es);
248   g_free (esds);
249 }
250
251 static AtomFRMA *
252 atom_frma_new ()
253 {
254   AtomFRMA *frma = g_new0 (AtomFRMA, 1);
255
256   atom_header_set (&frma->header, FOURCC_frma, 0, 0);
257   return frma;
258 }
259
260 static void
261 atom_frma_free (AtomFRMA * frma)
262 {
263   atom_clear (&frma->header);
264   g_free (frma);
265 }
266
267 static AtomWAVE *
268 atom_wave_new ()
269 {
270   AtomWAVE *wave = g_new0 (AtomWAVE, 1);
271
272   atom_header_set (&wave->header, FOURCC_wave, 0, 0);
273   return wave;
274 }
275
276 static void
277 atom_wave_free (AtomWAVE * wave)
278 {
279   atom_clear (&wave->header);
280   atom_info_list_free (wave->extension_atoms);
281   g_free (wave);
282 }
283
284 static void
285 atom_sample_entry_init (SampleTableEntry * se, guint32 type)
286 {
287   atom_header_set (&se->header, type, 0, 0);
288
289   memset (se->reserved, 0, sizeof (guint8) * 6);
290   se->data_reference_index = 0;
291 }
292
293 static void
294 atom_sample_entry_free (SampleTableEntry * se)
295 {
296   atom_clear (&se->header);
297 }
298
299 static void
300 sample_entry_mp4a_init (SampleTableEntryMP4A * mp4a)
301 {
302   atom_sample_entry_init (&mp4a->se, FOURCC_mp4a);
303
304   mp4a->version = 0;
305   mp4a->revision_level = 0;
306   mp4a->vendor = 0;
307   mp4a->channels = 2;
308   mp4a->sample_size = 16;
309   mp4a->compression_id = 0;
310   mp4a->packet_size = 0;
311   mp4a->sample_rate = 0;
312   /* following only used if version is 1 */
313   mp4a->samples_per_packet = 0;
314   mp4a->bytes_per_packet = 0;
315   mp4a->bytes_per_frame = 0;
316   mp4a->bytes_per_sample = 0;
317
318   mp4a->extension_atoms = NULL;
319 }
320
321 static SampleTableEntryMP4A *
322 sample_entry_mp4a_new ()
323 {
324   SampleTableEntryMP4A *mp4a = g_new0 (SampleTableEntryMP4A, 1);
325
326   sample_entry_mp4a_init (mp4a);
327   return mp4a;
328 }
329
330 static void
331 sample_entry_mp4a_free (SampleTableEntryMP4A * mp4a)
332 {
333   atom_sample_entry_free (&mp4a->se);
334   atom_info_list_free (mp4a->extension_atoms);
335   g_free (mp4a);
336 }
337
338 static void
339 sample_entry_mp4v_init (SampleTableEntryMP4V * mp4v, AtomsContext * context)
340 {
341   atom_sample_entry_init (&mp4v->se, FOURCC_mp4v);
342
343   mp4v->version = 0;
344   mp4v->revision_level = 0;
345   mp4v->vendor = 0;
346
347   mp4v->temporal_quality = 0;
348   mp4v->spatial_quality = 0;
349
350   /* qt and ISO base media do not contradict, and examples agree */
351   mp4v->horizontal_resolution = 0x00480000;
352   mp4v->vertical_resolution = 0x00480000;
353
354   mp4v->datasize = 0;
355   mp4v->frame_count = 1;
356
357   memset (mp4v->compressor, 0, sizeof (guint8) * 32);
358
359   mp4v->depth = 0;
360   mp4v->color_table_id = 0;
361
362   mp4v->extension_atoms = NULL;
363 }
364
365 static void
366 sample_entry_mp4v_free (SampleTableEntryMP4V * mp4v)
367 {
368   atom_sample_entry_free (&mp4v->se);
369   atom_info_list_free (mp4v->extension_atoms);
370   g_free (mp4v);
371 }
372
373 static SampleTableEntryMP4V *
374 sample_entry_mp4v_new (AtomsContext * context)
375 {
376   SampleTableEntryMP4V *mp4v = g_new0 (SampleTableEntryMP4V, 1);
377
378   sample_entry_mp4v_init (mp4v, context);
379   return mp4v;
380 }
381
382 static void
383 atom_stsd_init (AtomSTSD * stsd)
384 {
385   guint8 flags[3] = { 0, 0, 0 };
386
387   atom_full_init (&stsd->header, FOURCC_stsd, 0, 0, 0, flags);
388   stsd->entries = NULL;
389 }
390
391 static void
392 atom_stsd_clear (AtomSTSD * stsd)
393 {
394   GList *walker;
395
396   atom_full_clear (&stsd->header);
397   walker = stsd->entries;
398   while (walker) {
399     GList *aux = walker;
400     SampleTableEntry *se = (SampleTableEntry *) aux->data;
401
402     walker = g_list_next (walker);
403     stsd->entries = g_list_remove_link (stsd->entries, aux);
404
405     switch (se->kind) {
406       case AUDIO:
407         sample_entry_mp4a_free ((SampleTableEntryMP4A *) se);
408         break;
409       case VIDEO:
410         sample_entry_mp4v_free ((SampleTableEntryMP4V *) se);
411         break;
412       default:
413         /* best possible cleanup */
414         atom_sample_entry_free (se);
415     }
416     g_list_free (aux);
417   }
418 }
419
420 static void
421 atom_ctts_init (AtomCTTS * ctts)
422 {
423   guint8 flags[3] = { 0, 0, 0 };
424
425   atom_full_init (&ctts->header, FOURCC_ctts, 0, 0, 0, flags);
426   ctts->entries = NULL;
427 }
428
429 static AtomCTTS *
430 atom_ctts_new ()
431 {
432   AtomCTTS *ctts = g_new0 (AtomCTTS, 1);
433
434   atom_ctts_init (ctts);
435   return ctts;
436 }
437
438 static void
439 atom_ctts_free (AtomCTTS * ctts)
440 {
441   GList *walker;
442
443   atom_full_clear (&ctts->header);
444   walker = ctts->entries;
445   while (walker) {
446     GList *aux = walker;
447
448     walker = g_list_next (walker);
449     ctts->entries = g_list_remove_link (ctts->entries, aux);
450     g_free ((CTTSEntry *) aux->data);
451     g_list_free (aux);
452   }
453   g_free (ctts);
454 }
455
456 static void
457 atom_stts_init (AtomSTTS * stts)
458 {
459   guint8 flags[3] = { 0, 0, 0 };
460
461   atom_full_init (&stts->header, FOURCC_stts, 0, 0, 0, flags);
462   stts->entries = NULL;
463 }
464
465 static void
466 atom_stts_clear (AtomSTTS * stts)
467 {
468   GList *walker;
469
470   atom_full_clear (&stts->header);
471   walker = stts->entries;
472   while (walker) {
473     GList *aux = walker;
474
475     walker = g_list_next (walker);
476     stts->entries = g_list_remove_link (stts->entries, aux);
477     g_free ((STTSEntry *) aux->data);
478     g_list_free (aux);
479   }
480   stts->n_entries = 0;
481 }
482
483 static void
484 atom_stsz_init (AtomSTSZ * stsz)
485 {
486   guint8 flags[3] = { 0, 0, 0 };
487
488   atom_full_init (&stsz->header, FOURCC_stsz, 0, 0, 0, flags);
489   stsz->sample_size = 0;
490   stsz->table_size = 0;
491   stsz->entries = NULL;
492 }
493
494 static void
495 atom_stsz_clear (AtomSTSZ * stsz)
496 {
497   atom_full_clear (&stsz->header);
498   g_list_free (stsz->entries);
499   stsz->entries = NULL;
500   stsz->table_size = 0;
501 }
502
503 static void
504 atom_stsc_init (AtomSTSC * stsc)
505 {
506   guint8 flags[3] = { 0, 0, 0 };
507
508   atom_full_init (&stsc->header, FOURCC_stsc, 0, 0, 0, flags);
509   stsc->entries = NULL;
510   stsc->n_entries = 0;
511 }
512
513 static void
514 atom_stsc_clear (AtomSTSC * stsc)
515 {
516   GList *walker;
517
518   atom_full_clear (&stsc->header);
519   walker = stsc->entries;
520   while (walker) {
521     GList *aux = walker;
522
523     walker = g_list_next (walker);
524     stsc->entries = g_list_remove_link (stsc->entries, aux);
525     g_free ((STSCEntry *) aux->data);
526     g_list_free (aux);
527   }
528   stsc->n_entries = 0;
529 }
530
531 static void
532 atom_co64_init (AtomSTCO64 * co64)
533 {
534   guint8 flags[3] = { 0, 0, 0 };
535
536   atom_full_init (&co64->header, FOURCC_co64, 0, 0, 0, flags);
537   co64->entries = NULL;
538   co64->n_entries = 0;
539 }
540
541 static void
542 atom_stco64_clear (AtomSTCO64 * stco64)
543 {
544   GList *walker;
545
546   atom_full_clear (&stco64->header);
547   walker = stco64->entries;
548   while (walker) {
549     GList *aux = walker;
550
551     walker = g_list_next (walker);
552     stco64->entries = g_list_remove_link (stco64->entries, aux);
553     g_free ((guint64 *) aux->data);
554     g_list_free (aux);
555   }
556   stco64->n_entries = 0;
557 }
558
559 static void
560 atom_stss_init (AtomSTSS * stss)
561 {
562   guint8 flags[3] = { 0, 0, 0 };
563
564   atom_full_init (&stss->header, FOURCC_stss, 0, 0, 0, flags);
565   stss->entries = NULL;
566   stss->n_entries = 0;
567 }
568
569 static void
570 atom_stss_clear (AtomSTSS * stss)
571 {
572   atom_full_clear (&stss->header);
573   g_list_free (stss->entries);
574   stss->entries = NULL;
575   stss->n_entries = 0;
576 }
577
578 static void
579 atom_stbl_init (AtomSTBL * stbl)
580 {
581   atom_header_set (&stbl->header, FOURCC_stbl, 0, 0);
582
583   atom_stts_init (&stbl->stts);
584   atom_stss_init (&stbl->stss);
585   atom_stsd_init (&stbl->stsd);
586   atom_stsz_init (&stbl->stsz);
587   atom_stsc_init (&stbl->stsc);
588   stbl->ctts = NULL;
589
590   atom_co64_init (&stbl->stco64);
591 }
592
593 static void
594 atom_stbl_clear (AtomSTBL * stbl)
595 {
596   atom_clear (&stbl->header);
597   atom_stsd_clear (&stbl->stsd);
598   atom_stts_clear (&stbl->stts);
599   atom_stss_clear (&stbl->stss);
600   atom_stsc_clear (&stbl->stsc);
601   atom_stsz_clear (&stbl->stsz);
602   if (stbl->ctts) {
603     atom_ctts_free (stbl->ctts);
604   }
605   atom_stco64_clear (&stbl->stco64);
606 }
607
608 static void
609 atom_vmhd_init (AtomVMHD * vmhd, AtomsContext * context)
610 {
611   guint8 flags[3] = { 0, 0, 1 };
612
613   atom_full_init (&vmhd->header, FOURCC_vmhd, 0, 0, 0, flags);
614   vmhd->graphics_mode = 0x0;
615   memset (vmhd->opcolor, 0, sizeof (guint16) * 3);
616
617   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
618     vmhd->graphics_mode = 0x40;
619     vmhd->opcolor[0] = 32768;
620     vmhd->opcolor[1] = 32768;
621     vmhd->opcolor[2] = 32768;
622   }
623 }
624
625 static AtomVMHD *
626 atom_vmhd_new (AtomsContext * context)
627 {
628   AtomVMHD *vmhd = g_new0 (AtomVMHD, 1);
629
630   atom_vmhd_init (vmhd, context);
631   return vmhd;
632 }
633
634 static void
635 atom_vmhd_free (AtomVMHD * vmhd)
636 {
637   atom_full_clear (&vmhd->header);
638   g_free (vmhd);
639 }
640
641 static void
642 atom_smhd_init (AtomSMHD * smhd)
643 {
644   guint8 flags[3] = { 0, 0, 0 };
645
646   atom_full_init (&smhd->header, FOURCC_smhd, 0, 0, 0, flags);
647   smhd->balance = 0;
648   smhd->reserved = 0;
649 }
650
651 static AtomSMHD *
652 atom_smhd_new ()
653 {
654   AtomSMHD *smhd = g_new0 (AtomSMHD, 1);
655
656   atom_smhd_init (smhd);
657   return smhd;
658 }
659
660 static void
661 atom_smhd_free (AtomSMHD * smhd)
662 {
663   atom_full_clear (&smhd->header);
664   g_free (smhd);
665 }
666
667 static void
668 atom_hmhd_free (AtomHMHD * hmhd)
669 {
670   atom_full_clear (&hmhd->header);
671   g_free (hmhd);
672 }
673
674 static void
675 atom_hdlr_init (AtomHDLR * hdlr)
676 {
677   guint8 flags[3] = { 0, 0, 0 };
678
679   atom_full_init (&hdlr->header, FOURCC_hdlr, 0, 0, 0, flags);
680
681   hdlr->component_type = 0;
682   hdlr->handler_type = 0;
683   hdlr->manufacturer = 0;
684   hdlr->flags = 0;
685   hdlr->flags_mask = 0;
686   hdlr->name = g_strdup ("");
687 }
688
689 static AtomHDLR *
690 atom_hdlr_new ()
691 {
692   AtomHDLR *hdlr = g_new0 (AtomHDLR, 1);
693
694   atom_hdlr_init (hdlr);
695   return hdlr;
696 }
697
698 static void
699 atom_hdlr_clear (AtomHDLR * hdlr)
700 {
701   atom_full_clear (&hdlr->header);
702   if (hdlr->name) {
703     g_free (hdlr->name);
704     hdlr->name = NULL;
705   }
706 }
707
708 static void
709 atom_hdlr_free (AtomHDLR * hdlr)
710 {
711   atom_hdlr_clear (hdlr);
712   g_free (hdlr);
713 }
714
715 static void
716 atom_url_init (AtomURL * url)
717 {
718   guint8 flags[3] = { 0, 0, 1 };
719
720   atom_full_init (&url->header, FOURCC_url_, 0, 0, 0, flags);
721   url->location = NULL;
722 }
723
724 static void
725 atom_url_free (AtomURL * url)
726 {
727   atom_full_clear (&url->header);
728   if (url->location) {
729     g_free (url->location);
730     url->location = NULL;
731   }
732   g_free (url);
733 }
734
735 static AtomURL *
736 atom_url_new ()
737 {
738   AtomURL *url = g_new0 (AtomURL, 1);
739
740   atom_url_init (url);
741   return url;
742 }
743
744 static AtomFull *
745 atom_alis_new ()
746 {
747   guint8 flags[3] = { 0, 0, 1 };
748   AtomFull *alis = g_new0 (AtomFull, 1);
749
750   atom_full_init (alis, FOURCC_alis, 0, 0, 0, flags);
751   return alis;
752 }
753
754 static void
755 atom_dref_init (AtomDREF * dref, AtomsContext * context)
756 {
757   guint8 flags[3] = { 0, 0, 0 };
758
759   atom_full_init (&dref->header, FOURCC_dref, 0, 0, 0, flags);
760
761   /* in either case, alis or url init arranges to set self-contained flag */
762   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
763     /* alis dref for qt */
764     AtomFull *alis = atom_alis_new ();
765     dref->entries = g_list_append (dref->entries, alis);
766   } else {
767     /* url for iso spec, as 'alis' not specified there */
768     AtomURL *url = atom_url_new ();
769     dref->entries = g_list_append (dref->entries, url);
770   }
771 }
772
773 static void
774 atom_dref_clear (AtomDREF * dref)
775 {
776   GList *walker;
777
778   atom_full_clear (&dref->header);
779   walker = dref->entries;
780   while (walker) {
781     GList *aux = walker;
782     Atom *atom = (Atom *) aux->data;
783
784     walker = g_list_next (walker);
785     dref->entries = g_list_remove_link (dref->entries, aux);
786     switch (atom->type) {
787       case FOURCC_alis:
788         atom_full_free ((AtomFull *) atom);
789         break;
790       case FOURCC_url_:
791         atom_url_free ((AtomURL *) atom);
792         break;
793       default:
794         /* we do nothing, better leak than crash */
795         break;
796     }
797     g_list_free (aux);
798   }
799 }
800
801 static void
802 atom_dinf_init (AtomDINF * dinf, AtomsContext * context)
803 {
804   atom_header_set (&dinf->header, FOURCC_dinf, 0, 0);
805   atom_dref_init (&dinf->dref, context);
806 }
807
808 static void
809 atom_dinf_clear (AtomDINF * dinf)
810 {
811   atom_clear (&dinf->header);
812   atom_dref_clear (&dinf->dref);
813 }
814
815 static void
816 atom_minf_init (AtomMINF * minf, AtomsContext * context)
817 {
818   atom_header_set (&minf->header, FOURCC_minf, 0, 0);
819
820   minf->vmhd = NULL;
821   minf->smhd = NULL;
822   minf->hmhd = NULL;
823
824   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
825     minf->hdlr = atom_hdlr_new ();
826     minf->hdlr->component_type = FOURCC_dhlr;
827     minf->hdlr->handler_type = FOURCC_alis;
828   } else {
829     minf->hdlr = NULL;
830   }
831   atom_dinf_init (&minf->dinf, context);
832   atom_stbl_init (&minf->stbl);
833 }
834
835 static void
836 atom_minf_clear_handlers (AtomMINF * minf)
837 {
838   if (minf->vmhd) {
839     atom_vmhd_free (minf->vmhd);
840     minf->vmhd = NULL;
841   }
842   if (minf->smhd) {
843     atom_smhd_free (minf->smhd);
844     minf->smhd = NULL;
845   }
846   if (minf->hmhd) {
847     atom_hmhd_free (minf->hmhd);
848     minf->hmhd = NULL;
849   }
850 }
851
852 static void
853 atom_minf_clear (AtomMINF * minf)
854 {
855   atom_clear (&minf->header);
856   atom_minf_clear_handlers (minf);
857   if (minf->hdlr) {
858     atom_hdlr_free (minf->hdlr);
859   }
860   atom_dinf_clear (&minf->dinf);
861   atom_stbl_clear (&minf->stbl);
862 }
863
864 static void
865 atom_mdhd_init (AtomMDHD * mdhd)
866 {
867   guint8 flags[3] = { 0, 0, 0 };
868
869   atom_full_init (&mdhd->header, FOURCC_mdhd, 0, 0, 0, flags);
870   common_time_info_init (&mdhd->time_info);
871   mdhd->language_code = 0;
872   mdhd->quality = 0;
873 }
874
875 static void
876 atom_mdhd_clear (AtomMDHD * mdhd)
877 {
878   atom_full_clear (&mdhd->header);
879 }
880
881 static void
882 atom_mdia_init (AtomMDIA * mdia, AtomsContext * context)
883 {
884   atom_header_set (&mdia->header, FOURCC_mdia, 0, 0);
885
886   atom_mdhd_init (&mdia->mdhd);
887   atom_hdlr_init (&mdia->hdlr);
888   atom_minf_init (&mdia->minf, context);
889 }
890
891 static void
892 atom_mdia_clear (AtomMDIA * mdia)
893 {
894   atom_clear (&mdia->header);
895   atom_mdhd_clear (&mdia->mdhd);
896   atom_hdlr_clear (&mdia->hdlr);
897   atom_minf_clear (&mdia->minf);
898 }
899
900 static void
901 atom_tkhd_init (AtomTKHD * tkhd, AtomsContext * context)
902 {
903   /*
904    * flags info
905    * 1 -> track enabled
906    * 2 -> track in movie
907    * 4 -> track in preview
908    */
909   guint8 flags[3] = { 0, 0, 7 };
910
911   atom_full_init (&tkhd->header, FOURCC_tkhd, 0, 0, 0, flags);
912
913   tkhd->creation_time = tkhd->modification_time = get_current_qt_time ();
914   tkhd->duration = 0;
915   tkhd->track_ID = 0;
916   tkhd->reserved = 0;
917
918   tkhd->reserved2[0] = tkhd->reserved2[1] = 0;
919   tkhd->layer = 0;
920   tkhd->alternate_group = 0;
921   tkhd->volume = 0;
922   tkhd->reserved3 = 0;
923   memset (tkhd->matrix, 0, sizeof (guint32) * 9);
924   tkhd->matrix[0] = 1 << 16;
925   tkhd->matrix[4] = 1 << 16;
926   tkhd->matrix[8] = 16384 << 16;
927   tkhd->width = 0;
928   tkhd->height = 0;
929 }
930
931 static void
932 atom_tkhd_clear (AtomTKHD * tkhd)
933 {
934   atom_full_clear (&tkhd->header);
935 }
936
937 static void
938 atom_trak_init (AtomTRAK * trak, AtomsContext * context)
939 {
940   atom_header_set (&trak->header, FOURCC_trak, 0, 0);
941
942   atom_tkhd_init (&trak->tkhd, context);
943   atom_mdia_init (&trak->mdia, context);
944 }
945
946 AtomTRAK *
947 atom_trak_new (AtomsContext * context)
948 {
949   AtomTRAK *trak = g_new0 (AtomTRAK, 1);
950
951   atom_trak_init (trak, context);
952   return trak;
953 }
954
955 static void
956 atom_trak_free (AtomTRAK * trak)
957 {
958   atom_clear (&trak->header);
959   atom_tkhd_clear (&trak->tkhd);
960   atom_mdia_clear (&trak->mdia);
961   g_free (trak);
962 }
963
964 static void
965 atom_ilst_init (AtomILST * ilst)
966 {
967   atom_header_set (&ilst->header, FOURCC_ilst, 0, 0);
968   ilst->entries = NULL;
969 }
970
971 static AtomILST *
972 atom_ilst_new ()
973 {
974   AtomILST *ilst = g_new0 (AtomILST, 1);
975
976   atom_ilst_init (ilst);
977   return ilst;
978 }
979
980 static void
981 atom_ilst_free (AtomILST * ilst)
982 {
983   if (ilst->entries)
984     atom_info_list_free (ilst->entries);
985   atom_clear (&ilst->header);
986   g_free (ilst);
987 }
988
989 static void
990 atom_meta_init (AtomMETA * meta)
991 {
992   guint8 flags[3] = { 0, 0, 0 };
993
994   atom_full_init (&meta->header, FOURCC_meta, 0, 0, 0, flags);
995   atom_hdlr_init (&meta->hdlr);
996   /* FIXME (ISOM says this is always 0) */
997   meta->hdlr.component_type = FOURCC_mhlr;
998   meta->hdlr.handler_type = FOURCC_mdir;
999   meta->ilst = NULL;
1000 }
1001
1002 static AtomMETA *
1003 atom_meta_new ()
1004 {
1005   AtomMETA *meta = g_new0 (AtomMETA, 1);
1006
1007   atom_meta_init (meta);
1008   return meta;
1009 }
1010
1011 static void
1012 atom_meta_free (AtomMETA * meta)
1013 {
1014   atom_full_clear (&meta->header);
1015   atom_hdlr_clear (&meta->hdlr);
1016   atom_ilst_free (meta->ilst);
1017   meta->ilst = NULL;
1018   g_free (meta);
1019 }
1020
1021 static void
1022 atom_udta_init (AtomUDTA * udta)
1023 {
1024   atom_header_set (&udta->header, FOURCC_udta, 0, 0);
1025   udta->meta = NULL;
1026 }
1027
1028 static AtomUDTA *
1029 atom_udta_new ()
1030 {
1031   AtomUDTA *udta = g_new0 (AtomUDTA, 1);
1032
1033   atom_udta_init (udta);
1034   return udta;
1035 }
1036
1037 static void
1038 atom_udta_free (AtomUDTA * udta)
1039 {
1040   atom_clear (&udta->header);
1041   atom_meta_free (udta->meta);
1042   udta->meta = NULL;
1043   g_free (udta);
1044 }
1045
1046 static void
1047 atom_tag_data_init (AtomTagData * data)
1048 {
1049   guint8 flags[] = { 0, 0, 0 };
1050
1051   atom_full_init (&data->header, FOURCC_data, 0, 0, 0, flags);
1052 }
1053
1054 static void
1055 atom_tag_data_clear (AtomTagData * data)
1056 {
1057   atom_full_clear (&data->header);
1058   g_free (data->data);
1059   data->datalen = 0;
1060 }
1061
1062 /*
1063  * Fourcc is the tag fourcc
1064  * flags will be truncated to 24bits
1065  */
1066 static AtomTag *
1067 atom_tag_new (guint32 fourcc, guint32 flags_as_uint)
1068 {
1069   AtomTag *tag = g_new0 (AtomTag, 1);
1070
1071   tag->header.type = fourcc;
1072   atom_tag_data_init (&tag->data);
1073   tag->data.header.flags[2] = flags_as_uint & 0xFF;
1074   tag->data.header.flags[1] = flags_as_uint & 0xFF00;
1075   tag->data.header.flags[0] = flags_as_uint & 0xFF0000;
1076   return tag;
1077 }
1078
1079 static void
1080 atom_tag_free (AtomTag * tag)
1081 {
1082   atom_clear (&tag->header);
1083   atom_tag_data_clear (&tag->data);
1084   g_free (tag);
1085 }
1086
1087 static void
1088 atom_mvhd_init (AtomMVHD * mvhd)
1089 {
1090   guint8 flags[3] = { 0, 0, 0 };
1091
1092   atom_full_init (&(mvhd->header), FOURCC_mvhd, sizeof (AtomMVHD), 0, 0, flags);
1093
1094   common_time_info_init (&mvhd->time_info);
1095
1096   mvhd->prefered_rate = 1 << 16;
1097   mvhd->volume = 1 << 8;
1098   mvhd->reserved3 = 0;
1099   memset (mvhd->reserved4, 0, sizeof (guint32[2]));
1100
1101   memset (mvhd->matrix, 0, sizeof (guint32[9]));
1102   mvhd->matrix[0] = 1 << 16;
1103   mvhd->matrix[4] = 1 << 16;
1104   mvhd->matrix[8] = 16384 << 16;
1105
1106   mvhd->preview_time = 0;
1107   mvhd->preview_duration = 0;
1108   mvhd->poster_time = 0;
1109   mvhd->selection_time = 0;
1110   mvhd->selection_duration = 0;
1111   mvhd->current_time = 0;
1112
1113   mvhd->next_track_id = 1;
1114 }
1115
1116 static void
1117 atom_mvhd_clear (AtomMVHD * mvhd)
1118 {
1119   atom_full_clear (&mvhd->header);
1120 }
1121
1122 static void
1123 atom_moov_init (AtomMOOV * moov, AtomsContext * context)
1124 {
1125   atom_header_set (&(moov->header), FOURCC_moov, 0, 0);
1126   atom_mvhd_init (&(moov->mvhd));
1127   moov->udta = NULL;
1128   moov->traks = NULL;
1129 }
1130
1131 AtomMOOV *
1132 atom_moov_new (AtomsContext * context)
1133 {
1134   AtomMOOV *moov = g_new0 (AtomMOOV, 1);
1135
1136   atom_moov_init (moov, context);
1137   return moov;
1138 }
1139
1140 void
1141 atom_moov_free (AtomMOOV * moov)
1142 {
1143   GList *walker;
1144
1145   atom_clear (&moov->header);
1146   atom_mvhd_clear (&moov->mvhd);
1147
1148   walker = moov->traks;
1149   while (walker) {
1150     GList *aux = walker;
1151
1152     walker = g_list_next (walker);
1153     moov->traks = g_list_remove_link (moov->traks, aux);
1154     atom_trak_free ((AtomTRAK *) aux->data);
1155     g_list_free (aux);
1156   }
1157
1158   if (moov->udta) {
1159     atom_udta_free (moov->udta);
1160     moov->udta = NULL;
1161   }
1162
1163   g_free (moov);
1164 }
1165
1166 /* -- end of init / free -- */
1167
1168 /* -- copy data functions -- */
1169
1170 static guint8
1171 atom_full_get_version (AtomFull * full)
1172 {
1173   return full->version;
1174 }
1175
1176 static guint64
1177 common_time_info_copy_data (TimeInfo * ti, gboolean trunc_to_32,
1178     guint8 ** buffer, guint64 * size, guint64 * offset)
1179 {
1180   guint64 original_offset = *offset;
1181
1182   if (trunc_to_32) {
1183     prop_copy_uint32 ((guint32) ti->creation_time, buffer, size, offset);
1184     prop_copy_uint32 ((guint32) ti->modification_time, buffer, size, offset);
1185     prop_copy_uint32 (ti->timescale, buffer, size, offset);
1186     prop_copy_uint32 ((guint32) ti->duration, buffer, size, offset);
1187   } else {
1188     prop_copy_uint64 (ti->creation_time, buffer, size, offset);
1189     prop_copy_uint64 (ti->modification_time, buffer, size, offset);
1190     prop_copy_uint32 (ti->timescale, buffer, size, offset);
1191     prop_copy_uint64 (ti->duration, buffer, size, offset);
1192   }
1193   return *offset - original_offset;
1194 }
1195
1196 static void
1197 atom_write_size (guint8 ** buffer, guint64 * size, guint64 * offset,
1198     guint64 atom_pos)
1199 {
1200   /* this only works for non-extended atom size, which is OK
1201    * (though it could be made to do mem_move, etc and write extended size) */
1202   prop_copy_uint32 (*offset - atom_pos, buffer, size, &atom_pos);
1203 }
1204
1205 guint64
1206 atom_copy_data (Atom * atom, guint8 ** buffer, guint64 * size, guint64 * offset)
1207 {
1208   guint64 original_offset = *offset;
1209
1210   /* copies type and size */
1211   prop_copy_uint32 (atom->size, buffer, size, offset);
1212   prop_copy_fourcc (atom->type, buffer, size, offset);
1213
1214   /* extended size needed */
1215   if (atom->size == 1) {
1216     /* really should not happen other than with mdat atom;
1217      * would be a problem for size (re)write code, not to mention memory */
1218     g_return_val_if_fail (atom->type == FOURCC_mdat, 0);
1219     prop_copy_uint64 (atom->extended_size, buffer, size, offset);
1220   } else {
1221     /* just in case some trivially derived atom does not do so */
1222     atom_write_size (buffer, size, offset, original_offset);
1223   }
1224
1225   return *offset - original_offset;
1226 }
1227
1228 static guint64
1229 atom_full_copy_data (AtomFull * atom, guint8 ** buffer, guint64 * size,
1230     guint64 * offset)
1231 {
1232   guint64 original_offset = *offset;
1233
1234   if (!atom_copy_data (&atom->header, buffer, size, offset)) {
1235     return 0;
1236   }
1237
1238   prop_copy_uint8 (atom->version, buffer, size, offset);
1239   prop_copy_uint8_array (atom->flags, 3, buffer, size, offset);
1240
1241   atom_write_size (buffer, size, offset, original_offset);
1242   return *offset - original_offset;
1243 }
1244
1245 static guint64
1246 atom_info_list_copy_data (GList * ai, guint8 ** buffer, guint64 * size,
1247     guint64 * offset)
1248 {
1249   guint64 original_offset = *offset;
1250
1251   while (ai) {
1252     AtomInfo *info = (AtomInfo *) ai->data;
1253
1254     if (!info->copy_data_func (info->atom, buffer, size, offset)) {
1255       return 0;
1256     }
1257     ai = g_list_next (ai);
1258   }
1259
1260   return *offset - original_offset;
1261 }
1262
1263 static guint64
1264 atom_data_copy_data (AtomData * data, guint8 ** buffer, guint64 * size,
1265     guint64 * offset)
1266 {
1267   guint64 original_offset = *offset;
1268
1269   if (!atom_copy_data (&data->header, buffer, size, offset)) {
1270     return 0;
1271   }
1272   if (data->datalen)
1273     prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
1274
1275   atom_write_size (buffer, size, offset, original_offset);
1276   return *offset - original_offset;
1277 }
1278
1279 guint64
1280 atom_ftyp_copy_data (AtomFTYP * ftyp, guint8 ** buffer, guint64 * size,
1281     guint64 * offset)
1282 {
1283   guint64 original_offset = *offset;
1284
1285   if (!atom_copy_data (&ftyp->header, buffer, size, offset)) {
1286     return 0;
1287   }
1288   prop_copy_fourcc (ftyp->major_brand, buffer, size, offset);
1289   prop_copy_uint32 (ftyp->version, buffer, size, offset);
1290
1291   prop_copy_fourcc_array (ftyp->compatible_brands, ftyp->compatible_brands_size,
1292       buffer, size, offset);
1293
1294   atom_write_size (buffer, size, offset, original_offset);
1295   return *offset - original_offset;
1296 }
1297
1298 static guint64
1299 atom_mvhd_copy_data (AtomMVHD * atom, guint8 ** buffer, guint64 * size,
1300     guint64 * offset)
1301 {
1302   guint8 version;
1303   guint64 original_offset = *offset;
1304
1305   if (!atom_full_copy_data (&(atom->header), buffer, size, offset)) {
1306     return 0;
1307   }
1308
1309   version = atom_full_get_version (&(atom->header));
1310   if (version == 0) {
1311     common_time_info_copy_data (&atom->time_info, TRUE, buffer, size, offset);
1312   } else if (version == 1) {
1313     common_time_info_copy_data (&atom->time_info, FALSE, buffer, size, offset);
1314   } else {
1315     *offset = original_offset;
1316     return 0;
1317   }
1318
1319   prop_copy_uint32 (atom->prefered_rate, buffer, size, offset);
1320   prop_copy_uint16 (atom->volume, buffer, size, offset);
1321   prop_copy_uint16 (atom->reserved3, buffer, size, offset);
1322   prop_copy_uint32_array (atom->reserved4, 2, buffer, size, offset);
1323   prop_copy_uint32_array (atom->matrix, 9, buffer, size, offset);
1324   prop_copy_uint32 (atom->preview_time, buffer, size, offset);
1325   prop_copy_uint32 (atom->preview_duration, buffer, size, offset);
1326   prop_copy_uint32 (atom->poster_time, buffer, size, offset);
1327   prop_copy_uint32 (atom->selection_time, buffer, size, offset);
1328   prop_copy_uint32 (atom->selection_duration, buffer, size, offset);
1329   prop_copy_uint32 (atom->current_time, buffer, size, offset);
1330
1331   prop_copy_uint32 (atom->next_track_id, buffer, size, offset);
1332
1333   atom_write_size (buffer, size, offset, original_offset);
1334   return *offset - original_offset;
1335 }
1336
1337 static guint64
1338 atom_tkhd_copy_data (AtomTKHD * tkhd, guint8 ** buffer, guint64 * size,
1339     guint64 * offset)
1340 {
1341   guint64 original_offset = *offset;
1342
1343   if (!atom_full_copy_data (&tkhd->header, buffer, size, offset)) {
1344     return 0;
1345   }
1346
1347   if (atom_full_get_version (&tkhd->header) == 0) {
1348     prop_copy_uint32 ((guint32) tkhd->creation_time, buffer, size, offset);
1349     prop_copy_uint32 ((guint32) tkhd->modification_time, buffer, size, offset);
1350     prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
1351     prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
1352     prop_copy_uint32 ((guint32) tkhd->duration, buffer, size, offset);
1353   } else {
1354     prop_copy_uint64 (tkhd->creation_time, buffer, size, offset);
1355     prop_copy_uint64 (tkhd->modification_time, buffer, size, offset);
1356     prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
1357     prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
1358     prop_copy_uint64 (tkhd->duration, buffer, size, offset);
1359   }
1360
1361   prop_copy_uint32_array (tkhd->reserved2, 2, buffer, size, offset);
1362   prop_copy_uint16 (tkhd->layer, buffer, size, offset);
1363   prop_copy_uint16 (tkhd->alternate_group, buffer, size, offset);
1364   prop_copy_uint16 (tkhd->volume, buffer, size, offset);
1365   prop_copy_uint16 (tkhd->reserved3, buffer, size, offset);
1366   prop_copy_uint32_array (tkhd->matrix, 9, buffer, size, offset);
1367
1368   prop_copy_uint32 (tkhd->width, buffer, size, offset);
1369   prop_copy_uint32 (tkhd->height, buffer, size, offset);
1370
1371   atom_write_size (buffer, size, offset, original_offset);
1372   return *offset - original_offset;
1373 }
1374
1375 static guint64
1376 atom_hdlr_copy_data (AtomHDLR * hdlr, guint8 ** buffer, guint64 * size,
1377     guint64 * offset)
1378 {
1379   guint64 original_offset = *offset;
1380
1381   if (!atom_full_copy_data (&hdlr->header, buffer, size, offset)) {
1382     return 0;
1383   }
1384
1385   prop_copy_fourcc (hdlr->component_type, buffer, size, offset);
1386   prop_copy_fourcc (hdlr->handler_type, buffer, size, offset);
1387   prop_copy_fourcc (hdlr->manufacturer, buffer, size, offset);
1388   prop_copy_uint32 (hdlr->flags, buffer, size, offset);
1389   prop_copy_uint32 (hdlr->flags_mask, buffer, size, offset);
1390
1391   prop_copy_null_terminated_string (hdlr->name, buffer, size, offset);
1392
1393   atom_write_size (buffer, size, offset, original_offset);
1394   return *offset - original_offset;
1395 }
1396
1397 static guint64
1398 atom_vmhd_copy_data (AtomVMHD * vmhd, guint8 ** buffer, guint64 * size,
1399     guint64 * offset)
1400 {
1401   guint64 original_offset = *offset;
1402
1403   if (!atom_full_copy_data (&vmhd->header, buffer, size, offset)) {
1404     return 0;
1405   }
1406   prop_copy_uint16 (vmhd->graphics_mode, buffer, size, offset);
1407   prop_copy_uint16_array (vmhd->opcolor, 3, buffer, size, offset);
1408
1409   atom_write_size (buffer, size, offset, original_offset);
1410   return original_offset - *offset;
1411 }
1412
1413 static guint64
1414 atom_smhd_copy_data (AtomSMHD * smhd, guint8 ** buffer, guint64 * size,
1415     guint64 * offset)
1416 {
1417   guint64 original_offset = *offset;
1418
1419   if (!atom_full_copy_data (&smhd->header, buffer, size, offset)) {
1420     return 0;
1421   }
1422   prop_copy_uint16 (smhd->balance, buffer, size, offset);
1423   prop_copy_uint16 (smhd->reserved, buffer, size, offset);
1424
1425   atom_write_size (buffer, size, offset, original_offset);
1426   return original_offset - *offset;
1427 }
1428
1429 static guint64
1430 atom_hmhd_copy_data (AtomHMHD * hmhd, guint8 ** buffer, guint64 * size,
1431     guint64 * offset)
1432 {
1433   guint64 original_offset = *offset;
1434
1435   if (!atom_full_copy_data (&hmhd->header, buffer, size, offset)) {
1436     return 0;
1437   }
1438   prop_copy_uint16 (hmhd->max_pdu_size, buffer, size, offset);
1439   prop_copy_uint16 (hmhd->avg_pdu_size, buffer, size, offset);
1440   prop_copy_uint32 (hmhd->max_bitrate, buffer, size, offset);
1441   prop_copy_uint32 (hmhd->avg_bitrate, buffer, size, offset);
1442   prop_copy_uint32 (hmhd->sliding_avg_bitrate, buffer, size, offset);
1443
1444   atom_write_size (buffer, size, offset, original_offset);
1445   return original_offset - *offset;
1446 }
1447
1448 static gboolean
1449 atom_url_same_file_flag (AtomURL * url)
1450 {
1451   return (url->header.flags[2] & 0x1) == 1;
1452 }
1453
1454 static guint64
1455 atom_url_copy_data (AtomURL * url, guint8 ** buffer, guint64 * size,
1456     guint64 * offset)
1457 {
1458   guint64 original_offset = *offset;
1459
1460   if (!atom_full_copy_data (&url->header, buffer, size, offset)) {
1461     return 0;
1462   }
1463
1464   if (!atom_url_same_file_flag (url)) {
1465     prop_copy_null_terminated_string (url->location, buffer, size, offset);
1466   }
1467
1468   atom_write_size (buffer, size, offset, original_offset);
1469   return original_offset - *offset;
1470 }
1471
1472 static guint64
1473 atom_stts_copy_data (AtomSTTS * stts, guint8 ** buffer, guint64 * size,
1474     guint64 * offset)
1475 {
1476   guint64 original_offset = *offset;
1477   GList *walker;
1478
1479   if (!atom_full_copy_data (&stts->header, buffer, size, offset)) {
1480     return 0;
1481   }
1482
1483   prop_copy_uint32 (stts->n_entries, buffer, size, offset);
1484   /* minimize realloc */
1485   prop_copy_ensure_buffer (buffer, size, offset, 8 * stts->n_entries);
1486   for (walker = g_list_last (stts->entries); walker != NULL;
1487       walker = g_list_previous (walker)) {
1488     STTSEntry *entry = (STTSEntry *) walker->data;
1489
1490     prop_copy_uint32 (entry->sample_count, buffer, size, offset);
1491     prop_copy_int32 (entry->sample_delta, buffer, size, offset);
1492   }
1493
1494   atom_write_size (buffer, size, offset, original_offset);
1495   return *offset - original_offset;
1496 }
1497
1498 static guint64
1499 atom_sample_entry_copy_data (SampleTableEntry * se, guint8 ** buffer,
1500     guint64 * size, guint64 * offset)
1501 {
1502   guint64 original_offset = *offset;
1503
1504   if (!atom_copy_data (&se->header, buffer, size, offset)) {
1505     return 0;
1506   }
1507
1508   prop_copy_uint8_array (se->reserved, 6, buffer, size, offset);
1509   prop_copy_uint16 (se->data_reference_index, buffer, size, offset);
1510
1511   return *offset - original_offset;
1512 }
1513
1514 static guint64
1515 atom_esds_copy_data (AtomESDS * esds, guint8 ** buffer, guint64 * size,
1516     guint64 * offset)
1517 {
1518   guint64 original_offset = *offset;
1519
1520   if (!atom_full_copy_data (&esds->header, buffer, size, offset)) {
1521     return 0;
1522   }
1523   if (!desc_es_descriptor_copy_data (&esds->es, buffer, size, offset)) {
1524     return 0;
1525   }
1526
1527   atom_write_size (buffer, size, offset, original_offset);
1528   return *offset - original_offset;
1529 }
1530
1531 static guint64
1532 atom_frma_copy_data (AtomFRMA * frma, guint8 ** buffer,
1533     guint64 * size, guint64 * offset)
1534 {
1535   guint64 original_offset = *offset;
1536
1537   if (!atom_copy_data (&(frma->header), buffer, size, offset))
1538     return 0;
1539
1540   prop_copy_fourcc (frma->media_type, buffer, size, offset);
1541
1542   atom_write_size (buffer, size, offset, original_offset);
1543   return *offset - original_offset;
1544 }
1545
1546 static guint64
1547 atom_mp4s_copy_data (SampleTableEntryMP4S * mp4s, guint8 ** buffer,
1548     guint64 * size, guint64 * offset)
1549 {
1550   guint64 original_offset = *offset;
1551
1552   if (!atom_sample_entry_copy_data (&mp4s->se, buffer, size, offset)) {
1553     return 0;
1554   }
1555   if (!atom_esds_copy_data (&mp4s->es, buffer, size, offset)) {
1556     return 0;
1557   }
1558
1559   atom_write_size (buffer, size, offset, original_offset);
1560   return *offset - original_offset;
1561 }
1562
1563 static guint64
1564 atom_hint_sample_entry_copy_data (AtomHintSampleEntry * hse, guint8 ** buffer,
1565     guint64 * size, guint64 * offset)
1566 {
1567   guint64 original_offset = *offset;
1568
1569   if (!atom_sample_entry_copy_data (&hse->se, buffer, size, offset)) {
1570     return 0;
1571   }
1572
1573   prop_copy_uint32 (hse->size, buffer, size, offset);
1574   prop_copy_uint8_array (hse->data, hse->size, buffer, size, offset);
1575
1576   atom_write_size (buffer, size, offset, original_offset);
1577   return *offset - original_offset;
1578 }
1579
1580 static guint64
1581 sample_entry_mp4a_copy_data (SampleTableEntryMP4A * mp4a, guint8 ** buffer,
1582     guint64 * size, guint64 * offset)
1583 {
1584   guint64 original_offset = *offset;
1585
1586   if (!atom_sample_entry_copy_data (&mp4a->se, buffer, size, offset)) {
1587     return 0;
1588   }
1589
1590   prop_copy_uint16 (mp4a->version, buffer, size, offset);
1591   prop_copy_uint16 (mp4a->revision_level, buffer, size, offset);
1592   prop_copy_uint32 (mp4a->vendor, buffer, size, offset);
1593   prop_copy_uint16 (mp4a->channels, buffer, size, offset);
1594   prop_copy_uint16 (mp4a->sample_size, buffer, size, offset);
1595   prop_copy_uint16 (mp4a->compression_id, buffer, size, offset);
1596   prop_copy_uint16 (mp4a->packet_size, buffer, size, offset);
1597   prop_copy_uint32 (mp4a->sample_rate, buffer, size, offset);
1598
1599   /* this should always be 0 for mp4 flavor */
1600   if (mp4a->version == 1) {
1601     prop_copy_uint32 (mp4a->samples_per_packet, buffer, size, offset);
1602     prop_copy_uint32 (mp4a->bytes_per_packet, buffer, size, offset);
1603     prop_copy_uint32 (mp4a->bytes_per_frame, buffer, size, offset);
1604     prop_copy_uint32 (mp4a->bytes_per_sample, buffer, size, offset);
1605   }
1606
1607   if (mp4a->extension_atoms) {
1608     if (!atom_info_list_copy_data (mp4a->extension_atoms, buffer, size, offset))
1609       return 0;
1610   }
1611
1612   atom_write_size (buffer, size, offset, original_offset);
1613   return *offset - original_offset;
1614 }
1615
1616 static guint64
1617 sample_entry_mp4v_copy_data (SampleTableEntryMP4V * mp4v, guint8 ** buffer,
1618     guint64 * size, guint64 * offset)
1619 {
1620   guint64 original_offset = *offset;
1621
1622   if (!atom_sample_entry_copy_data (&mp4v->se, buffer, size, offset)) {
1623     return 0;
1624   }
1625
1626   prop_copy_uint16 (mp4v->version, buffer, size, offset);
1627   prop_copy_uint16 (mp4v->revision_level, buffer, size, offset);
1628   prop_copy_fourcc (mp4v->vendor, buffer, size, offset);
1629   prop_copy_uint32 (mp4v->temporal_quality, buffer, size, offset);
1630   prop_copy_uint32 (mp4v->spatial_quality, buffer, size, offset);
1631
1632   prop_copy_uint16 (mp4v->width, buffer, size, offset);
1633   prop_copy_uint16 (mp4v->height, buffer, size, offset);
1634
1635   prop_copy_uint32 (mp4v->horizontal_resolution, buffer, size, offset);
1636   prop_copy_uint32 (mp4v->vertical_resolution, buffer, size, offset);
1637   prop_copy_uint32 (mp4v->datasize, buffer, size, offset);
1638
1639   prop_copy_uint16 (mp4v->frame_count, buffer, size, offset);
1640
1641   prop_copy_fixed_size_string ((guint8 *) mp4v->compressor, 32, buffer, size,
1642       offset);
1643
1644   prop_copy_uint16 (mp4v->depth, buffer, size, offset);
1645   prop_copy_uint16 (mp4v->color_table_id, buffer, size, offset);
1646
1647   /* extra atoms */
1648   if (mp4v->extension_atoms &&
1649       !atom_info_list_copy_data (mp4v->extension_atoms, buffer, size, offset))
1650     return 0;
1651
1652   atom_write_size (buffer, size, offset, original_offset);
1653   return *offset - original_offset;
1654 }
1655
1656 static guint64
1657 atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
1658     guint64 * offset)
1659 {
1660   guint64 original_offset = *offset;
1661   GList *walker;
1662
1663   if (!atom_full_copy_data (&stsz->header, buffer, size, offset)) {
1664     return 0;
1665   }
1666
1667   prop_copy_uint32 (stsz->sample_size, buffer, size, offset);
1668   prop_copy_uint32 (stsz->table_size, buffer, size, offset);
1669   /* minimize realloc */
1670   prop_copy_ensure_buffer (buffer, size, offset, 4 * stsz->table_size);
1671   if (stsz->sample_size == 0) {
1672     for (walker = g_list_last (stsz->entries); walker != NULL;
1673         walker = g_list_previous (walker)) {
1674       prop_copy_uint32 ((guint32) GPOINTER_TO_UINT (walker->data), buffer, size,
1675           offset);
1676     }
1677   }
1678
1679   atom_write_size (buffer, size, offset, original_offset);
1680   return *offset - original_offset;
1681 }
1682
1683 static guint64
1684 atom_stsc_copy_data (AtomSTSC * stsc, guint8 ** buffer, guint64 * size,
1685     guint64 * offset)
1686 {
1687   guint64 original_offset = *offset;
1688   GList *walker;
1689
1690   if (!atom_full_copy_data (&stsc->header, buffer, size, offset)) {
1691     return 0;
1692   }
1693
1694   prop_copy_uint32 (stsc->n_entries, buffer, size, offset);
1695   /* minimize realloc */
1696   prop_copy_ensure_buffer (buffer, size, offset, 12 * stsc->n_entries);
1697
1698   for (walker = g_list_last (stsc->entries); walker != NULL;
1699       walker = g_list_previous (walker)) {
1700     STSCEntry *entry = (STSCEntry *) walker->data;
1701
1702     prop_copy_uint32 (entry->first_chunk, buffer, size, offset);
1703     prop_copy_uint32 (entry->samples_per_chunk, buffer, size, offset);
1704     prop_copy_uint32 (entry->sample_description_index, buffer, size, offset);
1705   }
1706
1707   atom_write_size (buffer, size, offset, original_offset);
1708   return *offset - original_offset;
1709 }
1710
1711 static guint64
1712 atom_ctts_copy_data (AtomCTTS * ctts, guint8 ** buffer, guint64 * size,
1713     guint64 * offset)
1714 {
1715   guint64 original_offset = *offset;
1716   GList *walker;
1717
1718   if (!atom_full_copy_data (&ctts->header, buffer, size, offset)) {
1719     return 0;
1720   }
1721
1722   prop_copy_uint32 (ctts->n_entries, buffer, size, offset);
1723   /* minimize realloc */
1724   prop_copy_ensure_buffer (buffer, size, offset, 8 * ctts->n_entries);
1725   for (walker = g_list_last (ctts->entries); walker != NULL;
1726       walker = g_list_previous (walker)) {
1727     CTTSEntry *entry = (CTTSEntry *) walker->data;
1728
1729     prop_copy_uint32 (entry->samplecount, buffer, size, offset);
1730     prop_copy_uint32 (entry->sampleoffset, buffer, size, offset);
1731   }
1732
1733   atom_write_size (buffer, size, offset, original_offset);
1734   return *offset - original_offset;
1735 }
1736
1737 static guint64
1738 atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size,
1739     guint64 * offset)
1740 {
1741   guint64 original_offset = *offset;
1742   GList *walker;
1743   gboolean trunc_to_32 = stco64->header.header.type == FOURCC_stco;
1744
1745   if (!atom_full_copy_data (&stco64->header, buffer, size, offset)) {
1746     return 0;
1747   }
1748
1749   prop_copy_uint32 (stco64->n_entries, buffer, size, offset);
1750
1751   /* minimize realloc */
1752   prop_copy_ensure_buffer (buffer, size, offset, 8 * stco64->n_entries);
1753   for (walker = g_list_last (stco64->entries); walker != NULL;
1754       walker = g_list_previous (walker)) {
1755     guint64 *value = (guint64 *) walker->data;
1756
1757     if (trunc_to_32) {
1758       prop_copy_uint32 ((guint32) * value, buffer, size, offset);
1759     } else {
1760       prop_copy_uint64 (*value, buffer, size, offset);
1761     }
1762   }
1763
1764   atom_write_size (buffer, size, offset, original_offset);
1765   return *offset - original_offset;
1766 }
1767
1768 static guint64
1769 atom_stss_copy_data (AtomSTSS * stss, guint8 ** buffer, guint64 * size,
1770     guint64 * offset)
1771 {
1772   guint64 original_offset = *offset;
1773   GList *walker;
1774
1775   if (stss->entries == NULL) {
1776     /* FIXME not needing this atom might be confused with error while copying */
1777     return 0;
1778   }
1779
1780   if (!atom_full_copy_data (&stss->header, buffer, size, offset)) {
1781     return 0;
1782   }
1783
1784   prop_copy_uint32 (stss->n_entries, buffer, size, offset);
1785   /* minimize realloc */
1786   prop_copy_ensure_buffer (buffer, size, offset, 4 * stss->n_entries);
1787   for (walker = g_list_last (stss->entries); walker != NULL;
1788       walker = g_list_previous (walker)) {
1789     prop_copy_uint32 ((guint32) GPOINTER_TO_UINT (walker->data), buffer, size,
1790         offset);
1791   }
1792
1793   atom_write_size (buffer, size, offset, original_offset);
1794   return *offset - original_offset;
1795 }
1796
1797 static guint64
1798 atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size,
1799     guint64 * offset)
1800 {
1801   guint64 original_offset = *offset;
1802   GList *walker;
1803
1804   if (!atom_full_copy_data (&stsd->header, buffer, size, offset)) {
1805     return 0;
1806   }
1807
1808   prop_copy_uint32 (stsd->n_entries, buffer, size, offset);
1809
1810   for (walker = g_list_last (stsd->entries); walker != NULL;
1811       walker = g_list_previous (walker)) {
1812     SampleTableEntry *se = (SampleTableEntry *) walker->data;
1813
1814     switch (((Atom *) walker->data)->type) {
1815       case FOURCC_mp4a:
1816         if (!sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) walker->data,
1817                 buffer, size, offset)) {
1818           return 0;
1819         }
1820         break;
1821       case FOURCC_mp4s:
1822         if (!atom_mp4s_copy_data ((SampleTableEntryMP4S *) walker->data,
1823                 buffer, size, offset)) {
1824           return 0;
1825         }
1826         break;
1827       case FOURCC_mp4v:
1828         if (!sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) walker->data,
1829                 buffer, size, offset)) {
1830           return 0;
1831         }
1832         break;
1833       default:
1834         if (se->kind == VIDEO) {
1835           size +=
1836               sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) walker->
1837               data, buffer, size, offset);
1838         } else if (se->kind == AUDIO) {
1839           size +=
1840               sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) walker->
1841               data, buffer, size, offset);
1842         } else {
1843           if (!atom_hint_sample_entry_copy_data (
1844                   (AtomHintSampleEntry *) walker->data, buffer, size, offset)) {
1845             return 0;
1846           }
1847         }
1848         break;
1849     }
1850   }
1851
1852   atom_write_size (buffer, size, offset, original_offset);
1853   return *offset - original_offset;
1854 }
1855
1856 static guint64
1857 atom_stbl_copy_data (AtomSTBL * stbl, guint8 ** buffer, guint64 * size,
1858     guint64 * offset)
1859 {
1860   guint64 original_offset = *offset;
1861
1862   if (!atom_copy_data (&stbl->header, buffer, size, offset)) {
1863     return 0;
1864   }
1865
1866   if (!atom_stsd_copy_data (&stbl->stsd, buffer, size, offset)) {
1867     return 0;
1868   }
1869   if (!atom_stts_copy_data (&stbl->stts, buffer, size, offset)) {
1870     return 0;
1871   }
1872   /* this atom is optional, so let's check if we need it
1873    * (to avoid false error) */
1874   if (stbl->stss.entries) {
1875     if (!atom_stss_copy_data (&stbl->stss, buffer, size, offset)) {
1876       return 0;
1877     }
1878   }
1879
1880   if (!atom_stsc_copy_data (&stbl->stsc, buffer, size, offset)) {
1881     return 0;
1882   }
1883   if (!atom_stsz_copy_data (&stbl->stsz, buffer, size, offset)) {
1884     return 0;
1885   }
1886   if (stbl->ctts) {
1887     if (!atom_ctts_copy_data (stbl->ctts, buffer, size, offset)) {
1888       return 0;
1889     }
1890   }
1891   if (!atom_stco64_copy_data (&stbl->stco64, buffer, size, offset)) {
1892     return 0;
1893   }
1894
1895   atom_write_size (buffer, size, offset, original_offset);
1896   return original_offset - *offset;
1897 }
1898
1899
1900 static guint64
1901 atom_dref_copy_data (AtomDREF * dref, guint8 ** buffer, guint64 * size,
1902     guint64 * offset)
1903 {
1904   guint64 original_offset = *offset;
1905   GList *walker;
1906
1907   if (!atom_full_copy_data (&dref->header, buffer, size, offset)) {
1908     return 0;
1909   }
1910
1911   prop_copy_uint32 (g_list_length (dref->entries), buffer, size, offset);
1912
1913   walker = dref->entries;
1914   while (walker != NULL) {
1915     Atom *atom = (Atom *) walker->data;
1916
1917     if (atom->type == FOURCC_url_) {
1918       atom_url_copy_data ((AtomURL *) atom, buffer, size, offset);
1919     } else if (atom->type == FOURCC_alis) {
1920       atom_full_copy_data ((AtomFull *) atom, buffer, size, offset);
1921     } else {
1922       g_error ("Unsupported atom used inside dref atom");
1923     }
1924     walker = g_list_next (walker);
1925   }
1926
1927   atom_write_size (buffer, size, offset, original_offset);
1928   return *offset - original_offset;
1929 }
1930
1931 static guint64
1932 atom_dinf_copy_data (AtomDINF * dinf, guint8 ** buffer, guint64 * size,
1933     guint64 * offset)
1934 {
1935   guint64 original_offset = *offset;
1936
1937   if (!atom_copy_data (&dinf->header, buffer, size, offset)) {
1938     return 0;
1939   }
1940
1941   if (!atom_dref_copy_data (&dinf->dref, buffer, size, offset)) {
1942     return 0;
1943   }
1944
1945   atom_write_size (buffer, size, offset, original_offset);
1946   return original_offset - *offset;
1947 }
1948
1949 static guint64
1950 atom_minf_copy_data (AtomMINF * minf, guint8 ** buffer, guint64 * size,
1951     guint64 * offset)
1952 {
1953   guint64 original_offset = *offset;
1954
1955   if (!atom_copy_data (&minf->header, buffer, size, offset)) {
1956     return 0;
1957   }
1958
1959   if (minf->vmhd) {
1960     if (!atom_vmhd_copy_data (minf->vmhd, buffer, size, offset)) {
1961       return 0;
1962     }
1963   } else if (minf->smhd) {
1964     if (!atom_smhd_copy_data (minf->smhd, buffer, size, offset)) {
1965       return 0;
1966     }
1967   } else if (minf->hmhd) {
1968     if (!atom_hmhd_copy_data (minf->hmhd, buffer, size, offset)) {
1969       return 0;
1970     }
1971   }
1972
1973   if (minf->hdlr) {
1974     if (!atom_hdlr_copy_data (minf->hdlr, buffer, size, offset)) {
1975       return 0;
1976     }
1977   }
1978
1979   if (!atom_dinf_copy_data (&minf->dinf, buffer, size, offset)) {
1980     return 0;
1981   }
1982   if (!atom_stbl_copy_data (&minf->stbl, buffer, size, offset)) {
1983     return 0;
1984   }
1985
1986   atom_write_size (buffer, size, offset, original_offset);
1987   return *offset - original_offset;
1988 }
1989
1990 static guint64
1991 atom_mdhd_copy_data (AtomMDHD * mdhd, guint8 ** buffer, guint64 * size,
1992     guint64 * offset)
1993 {
1994   guint64 original_offset = *offset;
1995
1996   if (!atom_full_copy_data (&mdhd->header, buffer, size, offset)) {
1997     return 0;
1998   }
1999
2000   if (!common_time_info_copy_data (&mdhd->time_info,
2001           atom_full_get_version (&mdhd->header) == 0, buffer, size, offset)) {
2002     return 0;
2003   }
2004
2005   prop_copy_uint16 (mdhd->language_code, buffer, size, offset);
2006   prop_copy_uint16 (mdhd->quality, buffer, size, offset);
2007
2008   atom_write_size (buffer, size, offset, original_offset);
2009   return *offset - original_offset;
2010 }
2011
2012 static guint64
2013 atom_mdia_copy_data (AtomMDIA * mdia, guint8 ** buffer, guint64 * size,
2014     guint64 * offset)
2015 {
2016   guint64 original_offset = *offset;
2017
2018   if (!atom_copy_data (&mdia->header, buffer, size, offset)) {
2019     return 0;
2020   }
2021   if (!atom_mdhd_copy_data (&mdia->mdhd, buffer, size, offset)) {
2022     return 0;
2023   }
2024   if (!atom_hdlr_copy_data (&mdia->hdlr, buffer, size, offset)) {
2025     return 0;
2026   }
2027
2028   if (!atom_minf_copy_data (&mdia->minf, buffer, size, offset)) {
2029     return 0;
2030   }
2031
2032   atom_write_size (buffer, size, offset, original_offset);
2033   return *offset - original_offset;
2034 }
2035
2036 static guint64
2037 atom_trak_copy_data (AtomTRAK * trak, guint8 ** buffer, guint64 * size,
2038     guint64 * offset)
2039 {
2040   guint64 original_offset = *offset;
2041
2042   if (!atom_copy_data (&trak->header, buffer, size, offset)) {
2043     return 0;
2044   }
2045   if (!atom_tkhd_copy_data (&trak->tkhd, buffer, size, offset)) {
2046     return 0;
2047   }
2048
2049   if (!atom_mdia_copy_data (&trak->mdia, buffer, size, offset)) {
2050     return 0;
2051   }
2052
2053   atom_write_size (buffer, size, offset, original_offset);
2054   return *offset - original_offset;
2055 }
2056
2057 static guint64
2058 atom_tag_data_copy_data (AtomTagData * data, guint8 ** buffer, guint64 * size,
2059     guint64 * offset)
2060 {
2061   guint64 original_offset = *offset;
2062
2063   if (!atom_full_copy_data (&data->header, buffer, size, offset)) {
2064     return 0;
2065   }
2066
2067   prop_copy_uint32 (data->reserved, buffer, size, offset);
2068   prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
2069
2070   atom_write_size (buffer, size, offset, original_offset);
2071   return *offset - original_offset;
2072 }
2073
2074 static guint64
2075 atom_tag_copy_data (AtomTag * tag, guint8 ** buffer, guint64 * size,
2076     guint64 * offset)
2077 {
2078   guint64 original_offset = *offset;
2079
2080   if (!atom_copy_data (&tag->header, buffer, size, offset)) {
2081     return 0;
2082   }
2083
2084   if (!atom_tag_data_copy_data (&tag->data, buffer, size, offset)) {
2085     return 0;
2086   }
2087
2088   atom_write_size (buffer, size, offset, original_offset);
2089   return *offset - original_offset;
2090 }
2091
2092 static guint64
2093 atom_ilst_copy_data (AtomILST * ilst, guint8 ** buffer, guint64 * size,
2094     guint64 * offset)
2095 {
2096   guint64 original_offset = *offset;
2097
2098   if (!atom_copy_data (&ilst->header, buffer, size, offset)) {
2099     return 0;
2100   }
2101   /* extra atoms */
2102   if (ilst->entries &&
2103       !atom_info_list_copy_data (ilst->entries, buffer, size, offset))
2104     return 0;
2105
2106   atom_write_size (buffer, size, offset, original_offset);
2107   return *offset - original_offset;
2108 }
2109
2110 static guint64
2111 atom_meta_copy_data (AtomMETA * meta, guint8 ** buffer, guint64 * size,
2112     guint64 * offset)
2113 {
2114   guint64 original_offset = *offset;
2115
2116   if (!atom_full_copy_data (&meta->header, buffer, size, offset)) {
2117     return 0;
2118   }
2119   if (!atom_hdlr_copy_data (&meta->hdlr, buffer, size, offset)) {
2120     return 0;
2121   }
2122   if (meta->ilst) {
2123     if (!atom_ilst_copy_data (meta->ilst, buffer, size, offset)) {
2124       return 0;
2125     }
2126   }
2127
2128   atom_write_size (buffer, size, offset, original_offset);
2129   return *offset - original_offset;
2130 }
2131
2132 static guint64
2133 atom_udta_copy_data (AtomUDTA * udta, guint8 ** buffer, guint64 * size,
2134     guint64 * offset)
2135 {
2136   guint64 original_offset = *offset;
2137
2138   if (!atom_copy_data (&udta->header, buffer, size, offset)) {
2139     return 0;
2140   }
2141   if (udta->meta) {
2142     if (!atom_meta_copy_data (udta->meta, buffer, size, offset)) {
2143       return 0;
2144     }
2145   }
2146
2147   atom_write_size (buffer, size, offset, original_offset);
2148   return *offset - original_offset;
2149 }
2150
2151 guint64
2152 atom_moov_copy_data (AtomMOOV * atom, guint8 ** buffer, guint64 * size,
2153     guint64 * offset)
2154 {
2155   guint64 original_offset = *offset;
2156   GList *walker;
2157
2158   if (!atom_copy_data (&(atom->header), buffer, size, offset))
2159     return 0;
2160
2161   if (!atom_mvhd_copy_data (&(atom->mvhd), buffer, size, offset))
2162     return 0;
2163
2164   walker = g_list_first (atom->traks);
2165   while (walker != NULL) {
2166     if (!atom_trak_copy_data ((AtomTRAK *) walker->data, buffer, size, offset)) {
2167       return 0;
2168     }
2169     walker = g_list_next (walker);
2170   }
2171
2172   if (atom->udta) {
2173     if (!atom_udta_copy_data (atom->udta, buffer, size, offset)) {
2174       return 0;
2175     }
2176   }
2177
2178   atom_write_size (buffer, size, offset, original_offset);
2179   return *offset - original_offset;
2180 }
2181
2182 static guint64
2183 atom_wave_copy_data (AtomWAVE * wave, guint8 ** buffer,
2184     guint64 * size, guint64 * offset)
2185 {
2186   guint64 original_offset = *offset;
2187
2188   if (!atom_copy_data (&(wave->header), buffer, size, offset))
2189     return 0;
2190
2191   if (wave->extension_atoms) {
2192     if (!atom_info_list_copy_data (wave->extension_atoms, buffer, size, offset))
2193       return 0;
2194   }
2195
2196   atom_write_size (buffer, size, offset, original_offset);
2197   return *offset - original_offset;
2198 }
2199
2200 /* -- end of copy data functions -- */
2201
2202 /* -- general functions, API and support functions */
2203
2204 /* add samples to tables */
2205
2206 static STSCEntry *
2207 stsc_entry_new (guint32 first_chunk, guint32 samples, guint32 desc_index)
2208 {
2209   STSCEntry *entry = g_new0 (STSCEntry, 1);
2210
2211   entry->first_chunk = first_chunk;
2212   entry->samples_per_chunk = samples;
2213   entry->sample_description_index = desc_index;
2214   return entry;
2215 }
2216
2217 static void
2218 atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
2219 {
2220   stsc->entries =
2221       g_list_prepend (stsc->entries, stsc_entry_new (first_chunk, nsamples, 1));
2222   stsc->n_entries++;
2223 }
2224
2225 static STTSEntry *
2226 stts_entry_new (guint32 sample_count, gint32 sample_delta)
2227 {
2228   STTSEntry *entry = g_new0 (STTSEntry, 1);
2229
2230   entry->sample_count = sample_count;
2231   entry->sample_delta = sample_delta;
2232   return entry;
2233 }
2234
2235 static void
2236 atom_stts_add_entry (AtomSTTS * stts, guint32 sample_count, gint32 sample_delta)
2237 {
2238   STTSEntry *entry;
2239
2240   if (stts->entries == NULL) {
2241     stts->entries =
2242         g_list_prepend (stts->entries, stts_entry_new (sample_count,
2243             sample_delta));
2244     stts->n_entries++;
2245     return;
2246   }
2247   entry = (STTSEntry *) g_list_first (stts->entries)->data;
2248   if (entry->sample_delta == sample_delta) {
2249     entry->sample_count += sample_count;
2250   } else {
2251     stts->entries =
2252         g_list_prepend (stts->entries, stts_entry_new (sample_count,
2253             sample_delta));
2254     stts->n_entries++;
2255   }
2256 }
2257
2258 static void
2259 atom_stsz_add_entry (AtomSTSZ * stsz, guint32 nsamples, guint32 size)
2260 {
2261   guint32 i;
2262
2263   stsz->table_size += nsamples;
2264   if (stsz->sample_size != 0) {
2265     /* it is constant size, we don't need entries */
2266     return;
2267   }
2268   for (i = 0; i < nsamples; i++) {
2269     stsz->entries = g_list_prepend (stsz->entries, GUINT_TO_POINTER (size));
2270   }
2271 }
2272
2273 static guint32
2274 atom_stco64_get_entry_count (AtomSTCO64 * stco64)
2275 {
2276   return stco64->n_entries;
2277 }
2278
2279 static void
2280 atom_stco64_add_entry (AtomSTCO64 * stco64, guint64 entry)
2281 {
2282   guint64 *pont = g_new (guint64, 1);
2283
2284   *pont = entry;
2285   stco64->entries = g_list_prepend (stco64->entries, pont);
2286   stco64->n_entries++;
2287 }
2288
2289 static void
2290 atom_stss_add_entry (AtomSTSS * stss, guint32 sample)
2291 {
2292   stss->entries = g_list_prepend (stss->entries, GUINT_TO_POINTER (sample));
2293   stss->n_entries++;
2294 }
2295
2296 static void
2297 atom_stbl_add_stss_entry (AtomSTBL * stbl)
2298 {
2299   guint32 sample_index = stbl->stsz.table_size;
2300
2301   atom_stss_add_entry (&stbl->stss, sample_index);
2302 }
2303
2304 static void
2305 atom_ctts_add_entry (AtomCTTS * ctts, guint32 nsamples, guint32 offset)
2306 {
2307   GList *walker;
2308   CTTSEntry *entry;
2309
2310   walker = g_list_first (ctts->entries);
2311   entry = (walker == NULL) ? NULL : (CTTSEntry *) walker->data;
2312
2313   if (entry == NULL || entry->sampleoffset != offset) {
2314     CTTSEntry *entry = g_new0 (CTTSEntry, 1);
2315
2316     entry->samplecount = nsamples;
2317     entry->sampleoffset = offset;
2318     ctts->entries = g_list_prepend (ctts->entries, entry);
2319     ctts->n_entries++;
2320   } else {
2321     entry->samplecount += nsamples;
2322   }
2323 }
2324
2325 static void
2326 atom_stbl_add_ctts_entry (AtomSTBL * stbl, guint32 nsamples, guint32 offset)
2327 {
2328   if (stbl->ctts == NULL) {
2329     stbl->ctts = atom_ctts_new ();
2330   }
2331   atom_ctts_add_entry (stbl->ctts, nsamples, offset);
2332 }
2333
2334 void
2335 atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta,
2336     guint32 size, guint64 chunk_offset, gboolean sync,
2337     gboolean do_pts, gint64 pts_offset)
2338 {
2339   AtomSTBL *stbl = &trak->mdia.minf.stbl;
2340
2341   atom_stts_add_entry (&stbl->stts, nsamples, delta);
2342   atom_stsz_add_entry (&stbl->stsz, nsamples, size);
2343   atom_stco64_add_entry (&stbl->stco64, chunk_offset);
2344   atom_stsc_add_new_entry (&stbl->stsc,
2345       atom_stco64_get_entry_count (&stbl->stco64), nsamples);
2346   if (sync)
2347     atom_stbl_add_stss_entry (stbl);
2348   if (do_pts)
2349     atom_stbl_add_ctts_entry (stbl, nsamples, pts_offset);
2350 }
2351
2352 /* trak and moov molding */
2353
2354 guint32
2355 atom_trak_get_timescale (AtomTRAK * trak)
2356 {
2357   return trak->mdia.mdhd.time_info.timescale;
2358 }
2359
2360 static void
2361 atom_trak_set_id (AtomTRAK * trak, guint32 id)
2362 {
2363   trak->tkhd.track_ID = id;
2364 }
2365
2366 void
2367 atom_moov_add_trak (AtomMOOV * moov, AtomTRAK * trak)
2368 {
2369   atom_trak_set_id (trak, moov->mvhd.next_track_id++);
2370   moov->traks = g_list_append (moov->traks, trak);
2371 }
2372
2373 static guint64
2374 atom_trak_get_duration (AtomTRAK * trak)
2375 {
2376   return trak->tkhd.duration;
2377 }
2378
2379 static guint64
2380 atom_stts_get_total_duration (AtomSTTS * stts)
2381 {
2382   GList *walker = stts->entries;
2383   guint64 sum = 0;
2384
2385   while (walker) {
2386     STTSEntry *entry = (STTSEntry *) walker->data;
2387
2388     sum += (guint64) (entry->sample_count) * entry->sample_delta;
2389     walker = g_list_next (walker);
2390   }
2391   return sum;
2392 }
2393
2394 static void
2395 atom_trak_update_duration (AtomTRAK * trak, guint64 moov_timescale)
2396 {
2397   trak->mdia.mdhd.time_info.duration =
2398       atom_stts_get_total_duration (&trak->mdia.minf.stbl.stts);
2399   trak->tkhd.duration =
2400       gst_util_uint64_scale (trak->mdia.mdhd.time_info.duration, moov_timescale,
2401       trak->mdia.mdhd.time_info.timescale);
2402 }
2403
2404 static guint32
2405 atom_moov_get_timescale (AtomMOOV * moov)
2406 {
2407   return moov->mvhd.time_info.timescale;
2408 }
2409
2410 void
2411 atom_moov_update_timescale (AtomMOOV * moov, guint32 timescale)
2412 {
2413   moov->mvhd.time_info.timescale = timescale;
2414 }
2415
2416 void
2417 atom_moov_update_duration (AtomMOOV * moov)
2418 {
2419   GList *traks = moov->traks;
2420   guint64 dur, duration = 0;
2421
2422   while (traks) {
2423     AtomTRAK *trak = (AtomTRAK *) traks->data;
2424
2425     atom_trak_update_duration (trak, atom_moov_get_timescale (moov));
2426     dur = atom_trak_get_duration (trak);
2427     if (dur > duration)
2428       duration = dur;
2429     traks = g_list_next (traks);
2430   }
2431   moov->mvhd.time_info.duration = duration;
2432 }
2433
2434 static void
2435 atom_set_type (Atom * atom, guint32 fourcc)
2436 {
2437   atom->type = fourcc;
2438 }
2439
2440 static void
2441 atom_stbl_set_64bits (AtomSTBL * stbl, gboolean use)
2442 {
2443   if (use) {
2444     atom_set_type (&stbl->stco64.header.header, FOURCC_co64);
2445   } else {
2446     atom_set_type (&stbl->stco64.header.header, FOURCC_stco);
2447   }
2448 }
2449
2450 static void
2451 atom_trak_set_64bits (AtomTRAK * trak, gboolean use)
2452 {
2453   atom_stbl_set_64bits (&trak->mdia.minf.stbl, use);
2454 }
2455
2456 void
2457 atom_moov_set_64bits (AtomMOOV * moov, gboolean large_file)
2458 {
2459   GList *traks = moov->traks;
2460
2461   while (traks) {
2462     AtomTRAK *trak = (AtomTRAK *) traks->data;
2463
2464     atom_trak_set_64bits (trak, large_file);
2465     traks = g_list_next (traks);
2466   }
2467 }
2468
2469 static void
2470 atom_stco64_chunks_add_offset (AtomSTCO64 * stco64, guint32 offset)
2471 {
2472   GList *entries = stco64->entries;
2473
2474   while (entries) {
2475     guint64 *value = (guint64 *) entries->data;
2476
2477     *value += offset;
2478     entries = g_list_next (entries);
2479   }
2480 }
2481
2482 void
2483 atom_moov_chunks_add_offset (AtomMOOV * moov, guint32 offset)
2484 {
2485   GList *traks = moov->traks;
2486
2487   while (traks) {
2488     AtomTRAK *trak = (AtomTRAK *) traks->data;
2489
2490     atom_stco64_chunks_add_offset (&trak->mdia.minf.stbl.stco64, offset);
2491     traks = g_list_next (traks);
2492   }
2493 }
2494
2495 /*
2496  * Meta tags functions
2497  */
2498 static void
2499 atom_moov_init_metatags (AtomMOOV * moov)
2500 {
2501   if (!moov->udta) {
2502     moov->udta = atom_udta_new ();
2503   }
2504   if (!moov->udta->meta) {
2505     moov->udta->meta = atom_meta_new ();
2506   }
2507   if (!moov->udta->meta->ilst) {
2508     moov->udta->meta->ilst = atom_ilst_new ();
2509   }
2510 }
2511
2512 static void
2513 atom_tag_data_alloc_data (AtomTagData * data, guint size)
2514 {
2515   if (data->data != NULL) {
2516     g_free (data->data);
2517   }
2518   data->data = g_new0 (guint8, size);
2519   data->datalen = size;
2520 }
2521
2522 static void
2523 atom_moov_append_tag (AtomMOOV * moov, AtomInfo * tag)
2524 {
2525   AtomILST *ilst;
2526
2527   ilst = moov->udta->meta->ilst;
2528   ilst->entries = g_list_append (ilst->entries, tag);
2529 }
2530
2531 void
2532 atom_moov_add_tag (AtomMOOV * moov, guint32 fourcc, guint32 flags,
2533     const guint8 * data, guint size)
2534 {
2535   AtomTag *tag;
2536   AtomTagData *tdata;
2537
2538   tag = atom_tag_new (fourcc, flags);
2539   tdata = &tag->data;
2540   atom_tag_data_alloc_data (tdata, size);
2541   g_memmove (tdata->data, data, size);
2542
2543   atom_moov_init_metatags (moov);
2544   atom_moov_append_tag (moov,
2545       build_atom_info_wrapper ((Atom *) tag, atom_tag_copy_data,
2546           atom_tag_free));
2547 }
2548
2549 void
2550 atom_moov_add_str_tag (AtomMOOV * moov, guint32 fourcc, const gchar * value)
2551 {
2552   gint len = strlen (value);
2553
2554   if (len > 0)
2555     atom_moov_add_tag (moov, fourcc, METADATA_TEXT_FLAG, (guint8 *) value, len);
2556 }
2557
2558 void
2559 atom_moov_add_uint_tag (AtomMOOV * moov, guint32 fourcc, guint32 flags,
2560     guint32 value)
2561 {
2562   guint8 data[8] = { 0, };
2563
2564   if (flags) {
2565     GST_WRITE_UINT16_BE (data, value);
2566     atom_moov_add_tag (moov, fourcc, flags, data, 2);
2567   } else {
2568     GST_WRITE_UINT32_BE (data + 2, value);
2569     atom_moov_add_tag (moov, fourcc, flags, data, 8);
2570   }
2571 }
2572
2573 void
2574 atom_moov_add_blob_tag (AtomMOOV * moov, guint8 * data, guint size)
2575 {
2576   AtomData *data_atom;
2577   GstBuffer *buf;
2578   guint len;
2579   guint32 fourcc;
2580
2581   if (size < 8)
2582     return;
2583
2584   /* blob is unparsed atom;
2585    * extract size and fourcc, and wrap remainder in data atom */
2586   len = GST_READ_UINT32_BE (data);
2587   fourcc = GST_READ_UINT32_LE (data + 4);
2588   if (len > size)
2589     return;
2590
2591   buf = gst_buffer_new ();
2592   GST_BUFFER_SIZE (buf) = len - 8;
2593   GST_BUFFER_DATA (buf) = data + 8;
2594
2595   data_atom = atom_data_new_from_gst_buffer (fourcc, buf);
2596   gst_buffer_unref (buf);
2597
2598   atom_moov_append_tag (moov,
2599       build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
2600           atom_data_free));
2601 }
2602
2603 /*
2604  * Functions for specifying media types
2605  */
2606
2607 static void
2608 atom_minf_set_audio (AtomMINF * minf)
2609 {
2610   atom_minf_clear_handlers (minf);
2611   minf->smhd = atom_smhd_new ();
2612 }
2613
2614 static void
2615 atom_minf_set_video (AtomMINF * minf, AtomsContext * context)
2616 {
2617   atom_minf_clear_handlers (minf);
2618   minf->vmhd = atom_vmhd_new (context);
2619 }
2620
2621 static void
2622 atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type,
2623     guint32 hdlr_type)
2624 {
2625   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
2626     hdlr->component_type = comp_type;
2627   }
2628   hdlr->handler_type = hdlr_type;
2629 }
2630
2631 static void
2632 atom_mdia_set_hdlr_type_audio (AtomMDIA * mdia, AtomsContext * context)
2633 {
2634   atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_soun);
2635 }
2636
2637 static void
2638 atom_mdia_set_hdlr_type_video (AtomMDIA * mdia, AtomsContext * context)
2639 {
2640   atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_vide);
2641 }
2642
2643 static void
2644 atom_mdia_set_audio (AtomMDIA * mdia, AtomsContext * context)
2645 {
2646   atom_mdia_set_hdlr_type_audio (mdia, context);
2647   atom_minf_set_audio (&mdia->minf);
2648 }
2649
2650 static void
2651 atom_mdia_set_video (AtomMDIA * mdia, AtomsContext * context)
2652 {
2653   atom_mdia_set_hdlr_type_video (mdia, context);
2654   atom_minf_set_video (&mdia->minf, context);
2655 }
2656
2657 static void
2658 atom_tkhd_set_audio (AtomTKHD * tkhd)
2659 {
2660   tkhd->volume = 0x0100;
2661   tkhd->width = tkhd->height = 0;
2662 }
2663
2664 static void
2665 atom_tkhd_set_video (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
2666     guint32 height)
2667 {
2668   tkhd->volume = 0;
2669
2670   /* qt and ISO base media do not contradict, and examples agree */
2671   tkhd->width = width;
2672   tkhd->height = height;
2673 }
2674
2675 /* re-negotiation is prevented at top-level, so only 1 entry expected.
2676  * Quite some more care here and elsewhere may be needed to
2677  * support several entries */
2678 static SampleTableEntryMP4A *
2679 atom_trak_add_audio_entry (AtomTRAK * trak, AtomsContext * context,
2680     guint32 type)
2681 {
2682   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
2683   SampleTableEntryMP4A *mp4a = sample_entry_mp4a_new ();
2684
2685   mp4a->se.header.type = type;
2686   mp4a->se.kind = AUDIO;
2687   mp4a->compression_id = -1;
2688   mp4a->se.data_reference_index = 1;
2689
2690   stsd->entries = g_list_prepend (stsd->entries, mp4a);
2691   stsd->n_entries++;
2692   return mp4a;
2693 }
2694
2695 static SampleTableEntryMP4V *
2696 atom_trak_add_video_entry (AtomTRAK * trak, AtomsContext * context,
2697     guint32 type)
2698 {
2699   SampleTableEntryMP4V *mp4v = sample_entry_mp4v_new (context);
2700   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
2701
2702   mp4v->se.header.type = type;
2703   mp4v->se.kind = VIDEO;
2704   mp4v->se.data_reference_index = 1;
2705   mp4v->horizontal_resolution = 72 << 16;
2706   mp4v->vertical_resolution = 72 << 16;
2707   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
2708     mp4v->spatial_quality = 512;
2709     mp4v->temporal_quality = 512;
2710   }
2711
2712   stsd->entries = g_list_prepend (stsd->entries, mp4v);
2713   stsd->n_entries++;
2714   return mp4v;
2715 }
2716
2717 static void
2718 atom_trak_set_constant_size_samples (AtomTRAK * trak, guint32 sample_size)
2719 {
2720   trak->mdia.minf.stbl.stsz.sample_size = sample_size;
2721 }
2722
2723 static void
2724 atom_trak_set_audio (AtomTRAK * trak, AtomsContext * context)
2725 {
2726   atom_tkhd_set_audio (&trak->tkhd);
2727   atom_mdia_set_audio (&trak->mdia, context);
2728 }
2729
2730 static void
2731 atom_trak_set_video (AtomTRAK * trak, AtomsContext * context, guint32 width,
2732     guint32 height)
2733 {
2734   atom_tkhd_set_video (&trak->tkhd, context, width, height);
2735   atom_mdia_set_video (&trak->mdia, context);
2736 }
2737
2738 static void
2739 atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context,
2740     guint32 rate)
2741 {
2742   atom_trak_set_audio (trak, context);
2743   trak->mdia.mdhd.time_info.timescale = rate;
2744 }
2745
2746 static void
2747 atom_trak_set_video_commons (AtomTRAK * trak, AtomsContext * context,
2748     guint32 rate, guint32 width, guint32 height)
2749 {
2750   atom_trak_set_video (trak, context, width, height);
2751   trak->mdia.mdhd.time_info.timescale = rate;
2752   trak->tkhd.width = width << 16;
2753   trak->tkhd.height = height << 16;
2754 }
2755
2756 void
2757 atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
2758     AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size)
2759 {
2760   SampleTableEntryMP4A *ste;
2761
2762   atom_trak_set_audio_commons (trak, context, scale);
2763   ste = atom_trak_add_audio_entry (trak, context, entry->fourcc);
2764
2765   ste->version = entry->version;
2766   ste->compression_id = entry->compression_id;
2767   ste->sample_size = entry->sample_size;
2768   ste->sample_rate = entry->sample_rate << 16;
2769   ste->channels = entry->channels;
2770
2771   ste->samples_per_packet = entry->samples_per_packet;
2772   ste->bytes_per_sample = entry->bytes_per_sample;
2773   ste->bytes_per_packet = entry->bytes_per_packet;
2774   ste->bytes_per_frame = entry->bytes_per_frame;
2775
2776   if (ext)
2777     ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext);
2778
2779   /* 0 size means variable size */
2780   atom_trak_set_constant_size_samples (trak, sample_size);
2781 }
2782
2783 void
2784 atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
2785     VisualSampleEntry * entry, guint32 scale, AtomInfo * ext)
2786 {
2787   SampleTableEntryMP4V *ste;
2788
2789   atom_trak_set_video_commons (trak, context, scale, entry->width,
2790       entry->height);
2791   ste = atom_trak_add_video_entry (trak, context, entry->fourcc);
2792
2793   ste->width = entry->width;
2794   ste->height = entry->height;
2795   ste->depth = entry->depth;
2796   ste->color_table_id = entry->color_table_id;
2797   ste->frame_count = entry->frame_count;
2798
2799   if (ext)
2800     ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext);
2801 }
2802
2803 /* some sample description construction helpers */
2804
2805 AtomInfo *
2806 build_esds_extension (AtomTRAK * trak, guint8 object_type, guint8 stream_type,
2807     const GstBuffer * codec_data)
2808 {
2809   guint32 track_id;
2810   AtomESDS *esds;
2811
2812   track_id = trak->tkhd.track_ID;
2813
2814   esds = atom_esds_new ();
2815   esds->es.id = track_id & 0xFFFF;
2816   esds->es.dec_conf_desc.object_type = object_type;
2817   esds->es.dec_conf_desc.stream_type = stream_type << 2 | 0x01;
2818
2819   /* optional DecoderSpecificInfo */
2820   if (codec_data) {
2821     DecoderSpecificInfoDescriptor *desc;
2822
2823     esds->es.dec_conf_desc.dec_specific_info = desc =
2824         desc_dec_specific_info_new ();
2825     desc_dec_specific_info_alloc_data (desc, GST_BUFFER_SIZE (codec_data));
2826
2827     memcpy (desc->data, GST_BUFFER_DATA (codec_data),
2828         GST_BUFFER_SIZE (codec_data));
2829   }
2830
2831   return build_atom_info_wrapper ((Atom *) esds, atom_esds_copy_data,
2832       atom_esds_free);
2833 }
2834
2835 AtomInfo *
2836 build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data)
2837 {
2838   guint32 track_id;
2839   AtomWAVE *wave;
2840   AtomFRMA *frma;
2841   Atom *ext_atom;
2842   GstBuffer *buf;
2843
2844   track_id = trak->tkhd.track_ID;
2845
2846   /* Add WAVE atom to the MP4A sample table entry */
2847   wave = atom_wave_new ();
2848
2849   /* Prepend Terminator atom to the WAVE list first, so it ends up last */
2850   ext_atom = (Atom *) atom_data_new (FOURCC_null);
2851   wave->extension_atoms =
2852       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
2853       (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
2854
2855   /* Add ESDS atom to WAVE */
2856   wave->extension_atoms = g_list_prepend (wave->extension_atoms,
2857       build_esds_extension (trak, ESDS_OBJECT_TYPE_MPEG4_P3,
2858           ESDS_STREAM_TYPE_AUDIO, codec_data));
2859
2860   /* Add MP4A atom to the WAVE:
2861    * not really in spec, but makes offset based players happy */
2862   buf = gst_buffer_new_and_alloc (4);
2863   *((guint32 *) GST_BUFFER_DATA (buf)) = 0;
2864   ext_atom = (Atom *) atom_data_new_from_gst_buffer (FOURCC_mp4a, buf);
2865   gst_buffer_unref (buf);
2866
2867   wave->extension_atoms =
2868       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
2869       (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
2870
2871   /* Add FRMA to the WAVE */
2872   frma = atom_frma_new ();
2873   frma->media_type = FOURCC_mp4a;
2874
2875   wave->extension_atoms =
2876       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
2877       (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
2878
2879   return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
2880       atom_wave_free);
2881 }
2882
2883 AtomInfo *
2884 build_jp2h_extension (AtomTRAK * trak, gint width, gint height, guint32 fourcc)
2885 {
2886   AtomData *atom_data;
2887   GstBuffer *buf;
2888   guint8 *data;
2889   guint8 cenum;
2890
2891   if (fourcc == GST_MAKE_FOURCC ('s', 'R', 'G', 'B')) {
2892     cenum = 0x10;
2893   } else if (fourcc == GST_MAKE_FOURCC ('s', 'Y', 'U', 'V')) {
2894     cenum = 0x12;
2895   } else
2896     return FALSE;
2897
2898   buf = gst_buffer_new_and_alloc (22 + 12);
2899   data = GST_BUFFER_DATA (buf);
2900
2901   /* ihdr = image header box */
2902   GST_WRITE_UINT32_BE (data, 22);
2903   GST_WRITE_UINT32_LE (data + 4, GST_MAKE_FOURCC ('i', 'h', 'd', 'r'));
2904   GST_WRITE_UINT32_BE (data + 8, height);
2905   GST_WRITE_UINT32_BE (data + 12, width);
2906   /* FIXME perhaps parse from stream,
2907    * though exactly 3 in any respectable colourspace */
2908   GST_WRITE_UINT16_BE (data + 16, 3);
2909   /* 8 bits per component, unsigned */
2910   GST_WRITE_UINT8 (data + 18, 0x7);
2911   /* compression type; reserved */
2912   GST_WRITE_UINT8 (data + 19, 0x7);
2913   /* colour space (un)known */
2914   GST_WRITE_UINT8 (data + 20, 0x0);
2915   /* intellectual property right (box present) */
2916   GST_WRITE_UINT8 (data + 21, 0x0);
2917
2918   /* colour specification box */
2919   data += 22;
2920   GST_WRITE_UINT32_BE (data, 12);
2921   GST_WRITE_UINT32_LE (data + 4, GST_MAKE_FOURCC ('c', 'o', 'l', 'r'));
2922   /* specification method: enumerated */
2923   GST_WRITE_UINT8 (data + 8, 0x1);
2924   /* precedence; reserved */
2925   GST_WRITE_UINT8 (data + 9, 0x0);
2926   /* approximation; reserved */
2927   GST_WRITE_UINT8 (data + 10, 0x0);
2928   /* enumerated colourspace */
2929   GST_WRITE_UINT8 (data + 11, cenum);
2930
2931   atom_data = atom_data_new_from_gst_buffer (FOURCC_jp2h, buf);
2932   gst_buffer_unref (buf);
2933
2934   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
2935       atom_data_free);
2936 }
2937
2938 AtomInfo *
2939 build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data)
2940 {
2941   AtomData *data;
2942   AtomInfo *result = NULL;
2943
2944   if (codec_data) {
2945     data = atom_data_new_from_gst_buffer (fourcc, codec_data);
2946     result = build_atom_info_wrapper ((Atom *) data, atom_data_copy_data,
2947         atom_data_free);
2948   }
2949
2950   return result;
2951 }