dc4eea0d7e9fcae823a87c823063c8ed06c34e05
[platform/upstream/gstreamer.git] / gst / isomp4 / atoms.c
1 /* Quicktime muxer plugin for GStreamer
2  * Copyright (C) 2008-2010 Thiago 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  * Unless otherwise indicated, Source Code is licensed under MIT license.
22  * See further explanation attached in License Statement (distributed in the file
23  * LICENSE).
24  *
25  * Permission is hereby granted, free of charge, to any person obtaining a copy of
26  * this software and associated documentation files (the "Software"), to deal in
27  * the Software without restriction, including without limitation the rights to
28  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
29  * of the Software, and to permit persons to whom the Software is furnished to do
30  * so, subject to the following conditions:
31  *
32  * The above copyright notice and this permission notice shall be included in all
33  * copies or substantial portions of the Software.
34  *
35  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
41  * SOFTWARE.
42  */
43
44 #include "atoms.h"
45 #include <string.h>
46 #include <glib.h>
47
48 #include <gst/gst.h>
49 #include <gst/base/gstbytewriter.h>
50 #include <gst/tag/tag.h>
51
52 /**
53  * Creates a new AtomsContext for the given flavor.
54  */
55 AtomsContext *
56 atoms_context_new (AtomsTreeFlavor flavor)
57 {
58   AtomsContext *context = g_new0 (AtomsContext, 1);
59   context->flavor = flavor;
60   return context;
61 }
62
63 /**
64  * Frees an AtomsContext and all memory associated with it
65  */
66 void
67 atoms_context_free (AtomsContext * context)
68 {
69   g_free (context);
70 }
71
72 /* -- creation, initialization, clear and free functions -- */
73
74 #define SECS_PER_DAY (24 * 60 * 60)
75 #define LEAP_YEARS_FROM_1904_TO_1970 17
76
77 static guint64
78 get_current_qt_time (void)
79 {
80   GTimeVal timeval;
81
82   g_get_current_time (&timeval);
83   /* FIXME this should use UTC coordinated time */
84   return timeval.tv_sec + (((1970 - 1904) * (guint64) 365) +
85       LEAP_YEARS_FROM_1904_TO_1970) * SECS_PER_DAY;
86 }
87
88 static void
89 common_time_info_init (TimeInfo * ti)
90 {
91   ti->creation_time = ti->modification_time = get_current_qt_time ();
92   ti->timescale = 0;
93   ti->duration = 0;
94 }
95
96 static void
97 atom_header_set (Atom * header, guint32 fourcc, gint32 size, gint64 ext_size)
98 {
99   header->type = fourcc;
100   header->size = size;
101   header->extended_size = ext_size;
102 }
103
104 static void
105 atom_clear (Atom * atom)
106 {
107 }
108
109 static void
110 atom_full_init (AtomFull * full, guint32 fourcc, gint32 size, gint64 ext_size,
111     guint8 version, guint8 flags[3])
112 {
113   atom_header_set (&(full->header), fourcc, size, ext_size);
114   full->version = version;
115   full->flags[0] = flags[0];
116   full->flags[1] = flags[1];
117   full->flags[2] = flags[2];
118 }
119
120 static void
121 atom_full_clear (AtomFull * full)
122 {
123   atom_clear (&full->header);
124 }
125
126 static void
127 atom_full_free (AtomFull * full)
128 {
129   atom_full_clear (full);
130   g_free (full);
131 }
132
133 static guint32
134 atom_full_get_flags_as_uint (AtomFull * full)
135 {
136   return full->flags[0] << 16 | full->flags[1] << 8 | full->flags[2];
137 }
138
139 static void
140 atom_full_set_flags_as_uint (AtomFull * full, guint32 flags_as_uint)
141 {
142   full->flags[2] = flags_as_uint & 0xFF;
143   full->flags[1] = (flags_as_uint & 0xFF00) >> 8;
144   full->flags[0] = (flags_as_uint & 0xFF0000) >> 16;
145 }
146
147 static AtomInfo *
148 build_atom_info_wrapper (Atom * atom, gpointer copy_func, gpointer free_func)
149 {
150   AtomInfo *info = NULL;
151
152   if (atom) {
153     info = g_new0 (AtomInfo, 1);
154
155     info->atom = atom;
156     info->copy_data_func = copy_func;
157     info->free_func = free_func;
158   }
159
160   return info;
161 }
162
163 static GList *
164 atom_info_list_prepend_atom (GList * ai, Atom * atom,
165     AtomCopyDataFunc copy_func, AtomFreeFunc free_func)
166 {
167   if (atom)
168     return g_list_prepend (ai,
169         build_atom_info_wrapper (atom, copy_func, free_func));
170   else
171     return ai;
172 }
173
174 static void
175 atom_info_list_free (GList * ai)
176 {
177   while (ai) {
178     AtomInfo *info = (AtomInfo *) ai->data;
179
180     info->free_func (info->atom);
181     g_free (info);
182     ai = g_list_delete_link (ai, ai);
183   }
184 }
185
186 static AtomData *
187 atom_data_new (guint32 fourcc)
188 {
189   AtomData *data = g_new0 (AtomData, 1);
190
191   atom_header_set (&data->header, fourcc, 0, 0);
192   return data;
193 }
194
195 static void
196 atom_data_alloc_mem (AtomData * data, guint32 size)
197 {
198   if (data->data) {
199     g_free (data->data);
200   }
201   data->data = g_new0 (guint8, size);
202   data->datalen = size;
203 }
204
205 static AtomData *
206 atom_data_new_from_gst_buffer (guint32 fourcc, const GstBuffer * buf)
207 {
208   AtomData *data = atom_data_new (fourcc);
209   gsize size = gst_buffer_get_size ((GstBuffer *) buf);
210
211   atom_data_alloc_mem (data, size);
212   gst_buffer_extract ((GstBuffer *) buf, 0, data->data, size);
213   return data;
214 }
215
216 static void
217 atom_data_free (AtomData * data)
218 {
219   atom_clear (&data->header);
220   g_free (data->data);
221   g_free (data);
222 }
223
224 static AtomUUID *
225 atom_uuid_new (void)
226 {
227   AtomUUID *uuid = g_new0 (AtomUUID, 1);
228
229   atom_header_set (&uuid->header, FOURCC_uuid, 0, 0);
230   return uuid;
231 }
232
233 static void
234 atom_uuid_free (AtomUUID * data)
235 {
236   atom_clear (&data->header);
237   g_free (data->data);
238   g_free (data);
239 }
240
241 static void
242 atom_ftyp_init (AtomFTYP * ftyp, guint32 major, guint32 version, GList * brands)
243 {
244   gint index;
245   GList *it = NULL;
246
247   atom_header_set (&ftyp->header, FOURCC_ftyp, 16, 0);
248   ftyp->major_brand = major;
249   ftyp->version = version;
250
251   /* always include major brand as compatible brand */
252   ftyp->compatible_brands_size = g_list_length (brands) + 1;
253   ftyp->compatible_brands = g_new (guint32, ftyp->compatible_brands_size);
254
255   ftyp->compatible_brands[0] = major;
256   index = 1;
257   for (it = brands; it != NULL; it = g_list_next (it)) {
258     ftyp->compatible_brands[index++] = GPOINTER_TO_UINT (it->data);
259   }
260 }
261
262 AtomFTYP *
263 atom_ftyp_new (AtomsContext * context, guint32 major, guint32 version,
264     GList * brands)
265 {
266   AtomFTYP *ftyp = g_new0 (AtomFTYP, 1);
267
268   atom_ftyp_init (ftyp, major, version, brands);
269   return ftyp;
270 }
271
272 void
273 atom_ftyp_free (AtomFTYP * ftyp)
274 {
275   atom_clear (&ftyp->header);
276   g_free (ftyp->compatible_brands);
277   ftyp->compatible_brands = NULL;
278   g_free (ftyp);
279 }
280
281 static void
282 atom_esds_init (AtomESDS * esds)
283 {
284   guint8 flags[3] = { 0, 0, 0 };
285
286   atom_full_init (&esds->header, FOURCC_esds, 0, 0, 0, flags);
287   desc_es_init (&esds->es);
288 }
289
290 static AtomESDS *
291 atom_esds_new (void)
292 {
293   AtomESDS *esds = g_new0 (AtomESDS, 1);
294
295   atom_esds_init (esds);
296   return esds;
297 }
298
299 static void
300 atom_esds_free (AtomESDS * esds)
301 {
302   atom_full_clear (&esds->header);
303   desc_es_descriptor_clear (&esds->es);
304   g_free (esds);
305 }
306
307 static AtomFRMA *
308 atom_frma_new (void)
309 {
310   AtomFRMA *frma = g_new0 (AtomFRMA, 1);
311
312   atom_header_set (&frma->header, FOURCC_frma, 0, 0);
313   return frma;
314 }
315
316 static void
317 atom_frma_free (AtomFRMA * frma)
318 {
319   atom_clear (&frma->header);
320   g_free (frma);
321 }
322
323 static AtomWAVE *
324 atom_wave_new (void)
325 {
326   AtomWAVE *wave = g_new0 (AtomWAVE, 1);
327
328   atom_header_set (&wave->header, FOURCC_wave, 0, 0);
329   return wave;
330 }
331
332 static void
333 atom_wave_free (AtomWAVE * wave)
334 {
335   atom_clear (&wave->header);
336   atom_info_list_free (wave->extension_atoms);
337   g_free (wave);
338 }
339
340 static void
341 atom_elst_init (AtomELST * elst)
342 {
343   guint8 flags[3] = { 0, 0, 0 };
344   atom_full_init (&elst->header, FOURCC_elst, 0, 0, 0, flags);
345   elst->entries = 0;
346 }
347
348 static void
349 atom_elst_clear (AtomELST * elst)
350 {
351   GSList *walker;
352
353   atom_full_clear (&elst->header);
354   walker = elst->entries;
355   while (walker) {
356     g_free ((EditListEntry *) walker->data);
357     walker = g_slist_next (walker);
358   }
359   g_slist_free (elst->entries);
360 }
361
362 static void
363 atom_edts_init (AtomEDTS * edts)
364 {
365   atom_header_set (&edts->header, FOURCC_edts, 0, 0);
366   atom_elst_init (&edts->elst);
367 }
368
369 static void
370 atom_edts_clear (AtomEDTS * edts)
371 {
372   atom_clear (&edts->header);
373   atom_elst_clear (&edts->elst);
374 }
375
376 static AtomEDTS *
377 atom_edts_new (void)
378 {
379   AtomEDTS *edts = g_new0 (AtomEDTS, 1);
380   atom_edts_init (edts);
381   return edts;
382 }
383
384 static void
385 atom_edts_free (AtomEDTS * edts)
386 {
387   atom_edts_clear (edts);
388   g_free (edts);
389 }
390
391 static void
392 atom_sample_entry_init (SampleTableEntry * se, guint32 type)
393 {
394   atom_header_set (&se->header, type, 0, 0);
395
396   memset (se->reserved, 0, sizeof (guint8) * 6);
397   se->data_reference_index = 0;
398 }
399
400 static void
401 atom_sample_entry_free (SampleTableEntry * se)
402 {
403   atom_clear (&se->header);
404 }
405
406 static void
407 sample_entry_mp4a_init (SampleTableEntryMP4A * mp4a)
408 {
409   atom_sample_entry_init (&mp4a->se, FOURCC_mp4a);
410
411   mp4a->version = 0;
412   mp4a->revision_level = 0;
413   mp4a->vendor = 0;
414   mp4a->channels = 2;
415   mp4a->sample_size = 16;
416   mp4a->compression_id = 0;
417   mp4a->packet_size = 0;
418   mp4a->sample_rate = 0;
419   /* following only used if version is 1 */
420   mp4a->samples_per_packet = 0;
421   mp4a->bytes_per_packet = 0;
422   mp4a->bytes_per_frame = 0;
423   mp4a->bytes_per_sample = 0;
424
425   mp4a->extension_atoms = NULL;
426 }
427
428 static SampleTableEntryMP4A *
429 sample_entry_mp4a_new (void)
430 {
431   SampleTableEntryMP4A *mp4a = g_new0 (SampleTableEntryMP4A, 1);
432
433   sample_entry_mp4a_init (mp4a);
434   return mp4a;
435 }
436
437 static void
438 sample_entry_mp4a_free (SampleTableEntryMP4A * mp4a)
439 {
440   atom_sample_entry_free (&mp4a->se);
441   atom_info_list_free (mp4a->extension_atoms);
442   g_free (mp4a);
443 }
444
445 static void
446 sample_entry_mp4v_init (SampleTableEntryMP4V * mp4v, AtomsContext * context)
447 {
448   atom_sample_entry_init (&mp4v->se, FOURCC_mp4v);
449
450   mp4v->version = 0;
451   mp4v->revision_level = 0;
452   mp4v->vendor = 0;
453
454   mp4v->temporal_quality = 0;
455   mp4v->spatial_quality = 0;
456
457   /* qt and ISO base media do not contradict, and examples agree */
458   mp4v->horizontal_resolution = 0x00480000;
459   mp4v->vertical_resolution = 0x00480000;
460
461   mp4v->datasize = 0;
462   mp4v->frame_count = 1;
463
464   memset (mp4v->compressor, 0, sizeof (guint8) * 32);
465
466   mp4v->depth = 0;
467   mp4v->color_table_id = 0;
468
469   mp4v->extension_atoms = NULL;
470 }
471
472 static void
473 sample_entry_mp4v_free (SampleTableEntryMP4V * mp4v)
474 {
475   atom_sample_entry_free (&mp4v->se);
476   atom_info_list_free (mp4v->extension_atoms);
477   g_free (mp4v);
478 }
479
480 static SampleTableEntryMP4V *
481 sample_entry_mp4v_new (AtomsContext * context)
482 {
483   SampleTableEntryMP4V *mp4v = g_new0 (SampleTableEntryMP4V, 1);
484
485   sample_entry_mp4v_init (mp4v, context);
486   return mp4v;
487 }
488
489 static void
490 atom_stsd_init (AtomSTSD * stsd)
491 {
492   guint8 flags[3] = { 0, 0, 0 };
493
494   atom_full_init (&stsd->header, FOURCC_stsd, 0, 0, 0, flags);
495   stsd->entries = NULL;
496   stsd->n_entries = 0;
497 }
498
499 static void
500 atom_stsd_remove_entries (AtomSTSD * stsd)
501 {
502   GList *walker;
503
504   walker = stsd->entries;
505   while (walker) {
506     GList *aux = walker;
507     SampleTableEntry *se = (SampleTableEntry *) aux->data;
508
509     walker = g_list_next (walker);
510     stsd->entries = g_list_remove_link (stsd->entries, aux);
511
512     switch (se->kind) {
513       case AUDIO:
514         sample_entry_mp4a_free ((SampleTableEntryMP4A *) se);
515         break;
516       case VIDEO:
517         sample_entry_mp4v_free ((SampleTableEntryMP4V *) se);
518         break;
519       default:
520         /* best possible cleanup */
521         atom_sample_entry_free (se);
522     }
523     g_list_free (aux);
524   }
525   stsd->n_entries = 0;
526 }
527
528 static void
529 atom_stsd_clear (AtomSTSD * stsd)
530 {
531   atom_stsd_remove_entries (stsd);
532   atom_full_clear (&stsd->header);
533 }
534
535 static void
536 atom_ctts_init (AtomCTTS * ctts)
537 {
538   guint8 flags[3] = { 0, 0, 0 };
539
540   atom_full_init (&ctts->header, FOURCC_ctts, 0, 0, 0, flags);
541   atom_array_init (&ctts->entries, 128);
542   ctts->do_pts = FALSE;
543 }
544
545 static AtomCTTS *
546 atom_ctts_new (void)
547 {
548   AtomCTTS *ctts = g_new0 (AtomCTTS, 1);
549
550   atom_ctts_init (ctts);
551   return ctts;
552 }
553
554 static void
555 atom_ctts_free (AtomCTTS * ctts)
556 {
557   atom_full_clear (&ctts->header);
558   atom_array_clear (&ctts->entries);
559   g_free (ctts);
560 }
561
562 static void
563 atom_stts_init (AtomSTTS * stts)
564 {
565   guint8 flags[3] = { 0, 0, 0 };
566
567   atom_full_init (&stts->header, FOURCC_stts, 0, 0, 0, flags);
568   atom_array_init (&stts->entries, 512);
569 }
570
571 static void
572 atom_stts_clear (AtomSTTS * stts)
573 {
574   atom_full_clear (&stts->header);
575   atom_array_clear (&stts->entries);
576 }
577
578 static void
579 atom_stsz_init (AtomSTSZ * stsz)
580 {
581   guint8 flags[3] = { 0, 0, 0 };
582
583   atom_full_init (&stsz->header, FOURCC_stsz, 0, 0, 0, flags);
584   atom_array_init (&stsz->entries, 1024);
585   stsz->sample_size = 0;
586   stsz->table_size = 0;
587 }
588
589 static void
590 atom_stsz_clear (AtomSTSZ * stsz)
591 {
592   atom_full_clear (&stsz->header);
593   atom_array_clear (&stsz->entries);
594   stsz->table_size = 0;
595 }
596
597 static void
598 atom_stsc_init (AtomSTSC * stsc)
599 {
600   guint8 flags[3] = { 0, 0, 0 };
601
602   atom_full_init (&stsc->header, FOURCC_stsc, 0, 0, 0, flags);
603   atom_array_init (&stsc->entries, 128);
604 }
605
606 static void
607 atom_stsc_clear (AtomSTSC * stsc)
608 {
609   atom_full_clear (&stsc->header);
610   atom_array_clear (&stsc->entries);
611 }
612
613 static void
614 atom_co64_init (AtomSTCO64 * co64)
615 {
616   guint8 flags[3] = { 0, 0, 0 };
617
618   atom_full_init (&co64->header, FOURCC_stco, 0, 0, 0, flags);
619   atom_array_init (&co64->entries, 256);
620 }
621
622 static void
623 atom_stco64_clear (AtomSTCO64 * stco64)
624 {
625   atom_full_clear (&stco64->header);
626   atom_array_clear (&stco64->entries);
627 }
628
629 static void
630 atom_stss_init (AtomSTSS * stss)
631 {
632   guint8 flags[3] = { 0, 0, 0 };
633
634   atom_full_init (&stss->header, FOURCC_stss, 0, 0, 0, flags);
635   atom_array_init (&stss->entries, 128);
636 }
637
638 static void
639 atom_stss_clear (AtomSTSS * stss)
640 {
641   atom_full_clear (&stss->header);
642   atom_array_clear (&stss->entries);
643 }
644
645 void
646 atom_stbl_init (AtomSTBL * stbl)
647 {
648   atom_header_set (&stbl->header, FOURCC_stbl, 0, 0);
649
650   atom_stts_init (&stbl->stts);
651   atom_stss_init (&stbl->stss);
652   atom_stsd_init (&stbl->stsd);
653   atom_stsz_init (&stbl->stsz);
654   atom_stsc_init (&stbl->stsc);
655   stbl->ctts = NULL;
656
657   atom_co64_init (&stbl->stco64);
658 }
659
660 void
661 atom_stbl_clear (AtomSTBL * stbl)
662 {
663   atom_clear (&stbl->header);
664   atom_stsd_clear (&stbl->stsd);
665   atom_stts_clear (&stbl->stts);
666   atom_stss_clear (&stbl->stss);
667   atom_stsc_clear (&stbl->stsc);
668   atom_stsz_clear (&stbl->stsz);
669   if (stbl->ctts) {
670     atom_ctts_free (stbl->ctts);
671   }
672   atom_stco64_clear (&stbl->stco64);
673 }
674
675 static void
676 atom_vmhd_init (AtomVMHD * vmhd, AtomsContext * context)
677 {
678   guint8 flags[3] = { 0, 0, 1 };
679
680   atom_full_init (&vmhd->header, FOURCC_vmhd, 0, 0, 0, flags);
681   vmhd->graphics_mode = 0x0;
682   memset (vmhd->opcolor, 0, sizeof (guint16) * 3);
683
684   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
685     vmhd->graphics_mode = 0x40;
686     vmhd->opcolor[0] = 32768;
687     vmhd->opcolor[1] = 32768;
688     vmhd->opcolor[2] = 32768;
689   }
690 }
691
692 static AtomVMHD *
693 atom_vmhd_new (AtomsContext * context)
694 {
695   AtomVMHD *vmhd = g_new0 (AtomVMHD, 1);
696
697   atom_vmhd_init (vmhd, context);
698   return vmhd;
699 }
700
701 static void
702 atom_vmhd_free (AtomVMHD * vmhd)
703 {
704   atom_full_clear (&vmhd->header);
705   g_free (vmhd);
706 }
707
708 static void
709 atom_smhd_init (AtomSMHD * smhd)
710 {
711   guint8 flags[3] = { 0, 0, 0 };
712
713   atom_full_init (&smhd->header, FOURCC_smhd, 0, 0, 0, flags);
714   smhd->balance = 0;
715   smhd->reserved = 0;
716 }
717
718 static AtomSMHD *
719 atom_smhd_new (void)
720 {
721   AtomSMHD *smhd = g_new0 (AtomSMHD, 1);
722
723   atom_smhd_init (smhd);
724   return smhd;
725 }
726
727 static void
728 atom_smhd_free (AtomSMHD * smhd)
729 {
730   atom_full_clear (&smhd->header);
731   g_free (smhd);
732 }
733
734 static void
735 atom_hmhd_free (AtomHMHD * hmhd)
736 {
737   atom_full_clear (&hmhd->header);
738   g_free (hmhd);
739 }
740
741 static void
742 atom_hdlr_init (AtomHDLR * hdlr)
743 {
744   guint8 flags[3] = { 0, 0, 0 };
745
746   atom_full_init (&hdlr->header, FOURCC_hdlr, 0, 0, 0, flags);
747
748   hdlr->component_type = 0;
749   hdlr->handler_type = 0;
750   hdlr->manufacturer = 0;
751   hdlr->flags = 0;
752   hdlr->flags_mask = 0;
753   hdlr->name = g_strdup ("");
754 }
755
756 static AtomHDLR *
757 atom_hdlr_new (void)
758 {
759   AtomHDLR *hdlr = g_new0 (AtomHDLR, 1);
760
761   atom_hdlr_init (hdlr);
762   return hdlr;
763 }
764
765 static void
766 atom_hdlr_clear (AtomHDLR * hdlr)
767 {
768   atom_full_clear (&hdlr->header);
769   if (hdlr->name) {
770     g_free (hdlr->name);
771     hdlr->name = NULL;
772   }
773 }
774
775 static void
776 atom_hdlr_free (AtomHDLR * hdlr)
777 {
778   atom_hdlr_clear (hdlr);
779   g_free (hdlr);
780 }
781
782 static void
783 atom_url_init (AtomURL * url)
784 {
785   guint8 flags[3] = { 0, 0, 1 };
786
787   atom_full_init (&url->header, FOURCC_url_, 0, 0, 0, flags);
788   url->location = NULL;
789 }
790
791 static void
792 atom_url_free (AtomURL * url)
793 {
794   atom_full_clear (&url->header);
795   if (url->location) {
796     g_free (url->location);
797     url->location = NULL;
798   }
799   g_free (url);
800 }
801
802 static AtomURL *
803 atom_url_new (void)
804 {
805   AtomURL *url = g_new0 (AtomURL, 1);
806
807   atom_url_init (url);
808   return url;
809 }
810
811 static AtomFull *
812 atom_alis_new (void)
813 {
814   guint8 flags[3] = { 0, 0, 1 };
815   AtomFull *alis = g_new0 (AtomFull, 1);
816
817   atom_full_init (alis, FOURCC_alis, 0, 0, 0, flags);
818   return alis;
819 }
820
821 static void
822 atom_dref_init (AtomDREF * dref, AtomsContext * context)
823 {
824   guint8 flags[3] = { 0, 0, 0 };
825
826   atom_full_init (&dref->header, FOURCC_dref, 0, 0, 0, flags);
827
828   /* in either case, alis or url init arranges to set self-contained flag */
829   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
830     /* alis dref for qt */
831     AtomFull *alis = atom_alis_new ();
832     dref->entries = g_list_append (dref->entries, alis);
833   } else {
834     /* url for iso spec, as 'alis' not specified there */
835     AtomURL *url = atom_url_new ();
836     dref->entries = g_list_append (dref->entries, url);
837   }
838 }
839
840 static void
841 atom_dref_clear (AtomDREF * dref)
842 {
843   GList *walker;
844
845   atom_full_clear (&dref->header);
846   walker = dref->entries;
847   while (walker) {
848     GList *aux = walker;
849     Atom *atom = (Atom *) aux->data;
850
851     walker = g_list_next (walker);
852     dref->entries = g_list_remove_link (dref->entries, aux);
853     switch (atom->type) {
854       case FOURCC_alis:
855         atom_full_free ((AtomFull *) atom);
856         break;
857       case FOURCC_url_:
858         atom_url_free ((AtomURL *) atom);
859         break;
860       default:
861         /* we do nothing, better leak than crash */
862         break;
863     }
864     g_list_free (aux);
865   }
866 }
867
868 static void
869 atom_dinf_init (AtomDINF * dinf, AtomsContext * context)
870 {
871   atom_header_set (&dinf->header, FOURCC_dinf, 0, 0);
872   atom_dref_init (&dinf->dref, context);
873 }
874
875 static void
876 atom_dinf_clear (AtomDINF * dinf)
877 {
878   atom_clear (&dinf->header);
879   atom_dref_clear (&dinf->dref);
880 }
881
882 static void
883 atom_minf_init (AtomMINF * minf, AtomsContext * context)
884 {
885   atom_header_set (&minf->header, FOURCC_minf, 0, 0);
886
887   minf->vmhd = NULL;
888   minf->smhd = NULL;
889   minf->hmhd = NULL;
890
891   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
892     minf->hdlr = atom_hdlr_new ();
893     minf->hdlr->component_type = FOURCC_dhlr;
894     minf->hdlr->handler_type = FOURCC_alis;
895   } else {
896     minf->hdlr = NULL;
897   }
898   atom_dinf_init (&minf->dinf, context);
899   atom_stbl_init (&minf->stbl);
900 }
901
902 static void
903 atom_minf_clear_handlers (AtomMINF * minf)
904 {
905   if (minf->vmhd) {
906     atom_vmhd_free (minf->vmhd);
907     minf->vmhd = NULL;
908   }
909   if (minf->smhd) {
910     atom_smhd_free (minf->smhd);
911     minf->smhd = NULL;
912   }
913   if (minf->hmhd) {
914     atom_hmhd_free (minf->hmhd);
915     minf->hmhd = NULL;
916   }
917 }
918
919 static void
920 atom_minf_clear (AtomMINF * minf)
921 {
922   atom_clear (&minf->header);
923   atom_minf_clear_handlers (minf);
924   if (minf->hdlr) {
925     atom_hdlr_free (minf->hdlr);
926   }
927   atom_dinf_clear (&minf->dinf);
928   atom_stbl_clear (&minf->stbl);
929 }
930
931 static void
932 atom_mdhd_init (AtomMDHD * mdhd)
933 {
934   guint8 flags[3] = { 0, 0, 0 };
935
936   atom_full_init (&mdhd->header, FOURCC_mdhd, 0, 0, 0, flags);
937   common_time_info_init (&mdhd->time_info);
938   mdhd->language_code = 0;
939   mdhd->quality = 0;
940 }
941
942 static void
943 atom_mdhd_clear (AtomMDHD * mdhd)
944 {
945   atom_full_clear (&mdhd->header);
946 }
947
948 static void
949 atom_mdia_init (AtomMDIA * mdia, AtomsContext * context)
950 {
951   atom_header_set (&mdia->header, FOURCC_mdia, 0, 0);
952
953   atom_mdhd_init (&mdia->mdhd);
954   atom_hdlr_init (&mdia->hdlr);
955   atom_minf_init (&mdia->minf, context);
956 }
957
958 static void
959 atom_mdia_clear (AtomMDIA * mdia)
960 {
961   atom_clear (&mdia->header);
962   atom_mdhd_clear (&mdia->mdhd);
963   atom_hdlr_clear (&mdia->hdlr);
964   atom_minf_clear (&mdia->minf);
965 }
966
967 static void
968 atom_tkhd_init (AtomTKHD * tkhd, AtomsContext * context)
969 {
970   /*
971    * flags info
972    * 1 -> track enabled
973    * 2 -> track in movie
974    * 4 -> track in preview
975    */
976   guint8 flags[3] = { 0, 0, 7 };
977
978   atom_full_init (&tkhd->header, FOURCC_tkhd, 0, 0, 0, flags);
979
980   tkhd->creation_time = tkhd->modification_time = get_current_qt_time ();
981   tkhd->duration = 0;
982   tkhd->track_ID = 0;
983   tkhd->reserved = 0;
984
985   tkhd->reserved2[0] = tkhd->reserved2[1] = 0;
986   tkhd->layer = 0;
987   tkhd->alternate_group = 0;
988   tkhd->volume = 0;
989   tkhd->reserved3 = 0;
990   memset (tkhd->matrix, 0, sizeof (guint32) * 9);
991   tkhd->matrix[0] = 1 << 16;
992   tkhd->matrix[4] = 1 << 16;
993   tkhd->matrix[8] = 16384 << 16;
994   tkhd->width = 0;
995   tkhd->height = 0;
996 }
997
998 static void
999 atom_tkhd_clear (AtomTKHD * tkhd)
1000 {
1001   atom_full_clear (&tkhd->header);
1002 }
1003
1004 static void
1005 atom_trak_init (AtomTRAK * trak, AtomsContext * context)
1006 {
1007   atom_header_set (&trak->header, FOURCC_trak, 0, 0);
1008
1009   atom_tkhd_init (&trak->tkhd, context);
1010   trak->edts = NULL;
1011   atom_mdia_init (&trak->mdia, context);
1012 }
1013
1014 AtomTRAK *
1015 atom_trak_new (AtomsContext * context)
1016 {
1017   AtomTRAK *trak = g_new0 (AtomTRAK, 1);
1018
1019   atom_trak_init (trak, context);
1020   return trak;
1021 }
1022
1023 static void
1024 atom_trak_clear (AtomTRAK * trak)
1025 {
1026   atom_clear (&trak->header);
1027   atom_tkhd_clear (&trak->tkhd);
1028   if (trak->edts)
1029     atom_edts_free (trak->edts);
1030   atom_mdia_clear (&trak->mdia);
1031 }
1032
1033 static void
1034 atom_trak_free (AtomTRAK * trak)
1035 {
1036   atom_trak_clear (trak);
1037   g_free (trak);
1038 }
1039
1040 static void
1041 atom_ilst_init (AtomILST * ilst)
1042 {
1043   atom_header_set (&ilst->header, FOURCC_ilst, 0, 0);
1044   ilst->entries = NULL;
1045 }
1046
1047 static AtomILST *
1048 atom_ilst_new (void)
1049 {
1050   AtomILST *ilst = g_new0 (AtomILST, 1);
1051
1052   atom_ilst_init (ilst);
1053   return ilst;
1054 }
1055
1056 static void
1057 atom_ilst_free (AtomILST * ilst)
1058 {
1059   if (ilst->entries)
1060     atom_info_list_free (ilst->entries);
1061   atom_clear (&ilst->header);
1062   g_free (ilst);
1063 }
1064
1065 static void
1066 atom_meta_init (AtomMETA * meta)
1067 {
1068   guint8 flags[3] = { 0, 0, 0 };
1069
1070   atom_full_init (&meta->header, FOURCC_meta, 0, 0, 0, flags);
1071   atom_hdlr_init (&meta->hdlr);
1072   /* FIXME (ISOM says this is always 0) */
1073   meta->hdlr.component_type = FOURCC_mhlr;
1074   meta->hdlr.handler_type = FOURCC_mdir;
1075   meta->ilst = NULL;
1076 }
1077
1078 static AtomMETA *
1079 atom_meta_new (void)
1080 {
1081   AtomMETA *meta = g_new0 (AtomMETA, 1);
1082
1083   atom_meta_init (meta);
1084   return meta;
1085 }
1086
1087 static void
1088 atom_meta_free (AtomMETA * meta)
1089 {
1090   atom_full_clear (&meta->header);
1091   atom_hdlr_clear (&meta->hdlr);
1092   if (meta->ilst)
1093     atom_ilst_free (meta->ilst);
1094   meta->ilst = NULL;
1095   g_free (meta);
1096 }
1097
1098 static void
1099 atom_udta_init (AtomUDTA * udta)
1100 {
1101   atom_header_set (&udta->header, FOURCC_udta, 0, 0);
1102   udta->meta = NULL;
1103 }
1104
1105 static AtomUDTA *
1106 atom_udta_new (void)
1107 {
1108   AtomUDTA *udta = g_new0 (AtomUDTA, 1);
1109
1110   atom_udta_init (udta);
1111   return udta;
1112 }
1113
1114 static void
1115 atom_udta_free (AtomUDTA * udta)
1116 {
1117   atom_clear (&udta->header);
1118   if (udta->meta)
1119     atom_meta_free (udta->meta);
1120   udta->meta = NULL;
1121   if (udta->entries)
1122     atom_info_list_free (udta->entries);
1123   g_free (udta);
1124 }
1125
1126 static void
1127 atom_tag_data_init (AtomTagData * data)
1128 {
1129   guint8 flags[] = { 0, 0, 0 };
1130
1131   atom_full_init (&data->header, FOURCC_data, 0, 0, 0, flags);
1132 }
1133
1134 static void
1135 atom_tag_data_clear (AtomTagData * data)
1136 {
1137   atom_full_clear (&data->header);
1138   g_free (data->data);
1139   data->datalen = 0;
1140 }
1141
1142 /*
1143  * Fourcc is the tag fourcc
1144  * flags will be truncated to 24bits
1145  */
1146 static AtomTag *
1147 atom_tag_new (guint32 fourcc, guint32 flags_as_uint)
1148 {
1149   AtomTag *tag = g_new0 (AtomTag, 1);
1150
1151   tag->header.type = fourcc;
1152   atom_tag_data_init (&tag->data);
1153   atom_full_set_flags_as_uint (&tag->data.header, flags_as_uint);
1154   return tag;
1155 }
1156
1157 static void
1158 atom_tag_free (AtomTag * tag)
1159 {
1160   atom_clear (&tag->header);
1161   atom_tag_data_clear (&tag->data);
1162   g_free (tag);
1163 }
1164
1165 static void
1166 atom_mvhd_init (AtomMVHD * mvhd)
1167 {
1168   guint8 flags[3] = { 0, 0, 0 };
1169
1170   atom_full_init (&(mvhd->header), FOURCC_mvhd, sizeof (AtomMVHD), 0, 0, flags);
1171
1172   common_time_info_init (&mvhd->time_info);
1173
1174   mvhd->prefered_rate = 1 << 16;
1175   mvhd->volume = 1 << 8;
1176   mvhd->reserved3 = 0;
1177   memset (mvhd->reserved4, 0, sizeof (guint32[2]));
1178
1179   memset (mvhd->matrix, 0, sizeof (guint32[9]));
1180   mvhd->matrix[0] = 1 << 16;
1181   mvhd->matrix[4] = 1 << 16;
1182   mvhd->matrix[8] = 16384 << 16;
1183
1184   mvhd->preview_time = 0;
1185   mvhd->preview_duration = 0;
1186   mvhd->poster_time = 0;
1187   mvhd->selection_time = 0;
1188   mvhd->selection_duration = 0;
1189   mvhd->current_time = 0;
1190
1191   mvhd->next_track_id = 1;
1192 }
1193
1194 static void
1195 atom_mvhd_clear (AtomMVHD * mvhd)
1196 {
1197   atom_full_clear (&mvhd->header);
1198 }
1199
1200 static void
1201 atom_mehd_init (AtomMEHD * mehd)
1202 {
1203   guint8 flags[3] = { 0, 0, 0 };
1204
1205   atom_full_init (&mehd->header, FOURCC_mehd, 0, 0, 1, flags);
1206   mehd->fragment_duration = 0;
1207 }
1208
1209 static void
1210 atom_mvex_init (AtomMVEX * mvex)
1211 {
1212   atom_header_set (&mvex->header, FOURCC_mvex, 0, 0);
1213   atom_mehd_init (&mvex->mehd);
1214   mvex->trexs = NULL;
1215 }
1216
1217 static void
1218 atom_moov_init (AtomMOOV * moov, AtomsContext * context)
1219 {
1220   atom_header_set (&(moov->header), FOURCC_moov, 0, 0);
1221   atom_mvhd_init (&(moov->mvhd));
1222   atom_mvex_init (&(moov->mvex));
1223   moov->udta = NULL;
1224   moov->traks = NULL;
1225   moov->context = *context;
1226 }
1227
1228 AtomMOOV *
1229 atom_moov_new (AtomsContext * context)
1230 {
1231   AtomMOOV *moov = g_new0 (AtomMOOV, 1);
1232
1233   atom_moov_init (moov, context);
1234   return moov;
1235 }
1236
1237 static void
1238 atom_trex_free (AtomTREX * trex)
1239 {
1240   atom_full_clear (&trex->header);
1241   g_free (trex);
1242 }
1243
1244 static void
1245 atom_mvex_clear (AtomMVEX * mvex)
1246 {
1247   GList *walker;
1248
1249   atom_clear (&mvex->header);
1250   walker = mvex->trexs;
1251   while (walker) {
1252     atom_trex_free ((AtomTREX *) walker->data);
1253     walker = g_list_next (walker);
1254   }
1255   g_list_free (mvex->trexs);
1256   mvex->trexs = NULL;
1257 }
1258
1259 void
1260 atom_moov_free (AtomMOOV * moov)
1261 {
1262   GList *walker;
1263
1264   atom_clear (&moov->header);
1265   atom_mvhd_clear (&moov->mvhd);
1266
1267   walker = moov->traks;
1268   while (walker) {
1269     atom_trak_free ((AtomTRAK *) walker->data);
1270     walker = g_list_next (walker);
1271   }
1272   g_list_free (moov->traks);
1273   moov->traks = NULL;
1274
1275   if (moov->udta) {
1276     atom_udta_free (moov->udta);
1277     moov->udta = NULL;
1278   }
1279
1280   atom_mvex_clear (&moov->mvex);
1281
1282   g_free (moov);
1283 }
1284
1285 /* -- end of init / free -- */
1286
1287 /* -- copy data functions -- */
1288
1289 static guint8
1290 atom_full_get_version (AtomFull * full)
1291 {
1292   return full->version;
1293 }
1294
1295 static guint64
1296 common_time_info_copy_data (TimeInfo * ti, gboolean trunc_to_32,
1297     guint8 ** buffer, guint64 * size, guint64 * offset)
1298 {
1299   guint64 original_offset = *offset;
1300
1301   if (trunc_to_32) {
1302     prop_copy_uint32 ((guint32) ti->creation_time, buffer, size, offset);
1303     prop_copy_uint32 ((guint32) ti->modification_time, buffer, size, offset);
1304     prop_copy_uint32 (ti->timescale, buffer, size, offset);
1305     prop_copy_uint32 ((guint32) ti->duration, buffer, size, offset);
1306   } else {
1307     prop_copy_uint64 (ti->creation_time, buffer, size, offset);
1308     prop_copy_uint64 (ti->modification_time, buffer, size, offset);
1309     prop_copy_uint32 (ti->timescale, buffer, size, offset);
1310     prop_copy_uint64 (ti->duration, buffer, size, offset);
1311   }
1312   return *offset - original_offset;
1313 }
1314
1315 static void
1316 atom_write_size (guint8 ** buffer, guint64 * size, guint64 * offset,
1317     guint64 atom_pos)
1318 {
1319   /* this only works for non-extended atom size, which is OK
1320    * (though it could be made to do mem_move, etc and write extended size) */
1321   prop_copy_uint32 (*offset - atom_pos, buffer, size, &atom_pos);
1322 }
1323
1324 guint64
1325 atom_copy_data (Atom * atom, guint8 ** buffer, guint64 * size, guint64 * offset)
1326 {
1327   guint64 original_offset = *offset;
1328
1329   /* copies type and size */
1330   prop_copy_uint32 (atom->size, buffer, size, offset);
1331   prop_copy_fourcc (atom->type, buffer, size, offset);
1332
1333   /* extended size needed */
1334   if (atom->size == 1) {
1335     /* really should not happen other than with mdat atom;
1336      * would be a problem for size (re)write code, not to mention memory */
1337     g_return_val_if_fail (atom->type == FOURCC_mdat, 0);
1338     prop_copy_uint64 (atom->extended_size, buffer, size, offset);
1339   }
1340
1341   return *offset - original_offset;
1342 }
1343
1344 static guint64
1345 atom_full_copy_data (AtomFull * atom, guint8 ** buffer, guint64 * size,
1346     guint64 * offset)
1347 {
1348   guint64 original_offset = *offset;
1349
1350   if (!atom_copy_data (&atom->header, buffer, size, offset)) {
1351     return 0;
1352   }
1353
1354   prop_copy_uint8 (atom->version, buffer, size, offset);
1355   prop_copy_uint8_array (atom->flags, 3, buffer, size, offset);
1356
1357   atom_write_size (buffer, size, offset, original_offset);
1358   return *offset - original_offset;
1359 }
1360
1361 static guint64
1362 atom_info_list_copy_data (GList * ai, guint8 ** buffer, guint64 * size,
1363     guint64 * offset)
1364 {
1365   guint64 original_offset = *offset;
1366
1367   while (ai) {
1368     AtomInfo *info = (AtomInfo *) ai->data;
1369
1370     if (!info->copy_data_func (info->atom, buffer, size, offset)) {
1371       return 0;
1372     }
1373     ai = g_list_next (ai);
1374   }
1375
1376   return *offset - original_offset;
1377 }
1378
1379 static guint64
1380 atom_data_copy_data (AtomData * data, guint8 ** buffer, guint64 * size,
1381     guint64 * offset)
1382 {
1383   guint64 original_offset = *offset;
1384
1385   if (!atom_copy_data (&data->header, buffer, size, offset)) {
1386     return 0;
1387   }
1388   if (data->datalen)
1389     prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
1390
1391   atom_write_size (buffer, size, offset, original_offset);
1392   return *offset - original_offset;
1393 }
1394
1395 static guint64
1396 atom_uuid_copy_data (AtomUUID * uuid, guint8 ** buffer, guint64 * size,
1397     guint64 * offset)
1398 {
1399   guint64 original_offset = *offset;
1400
1401   if (!atom_copy_data (&uuid->header, buffer, size, offset)) {
1402     return 0;
1403   }
1404   prop_copy_uint8_array (uuid->uuid, 16, buffer, size, offset);
1405   if (uuid->datalen)
1406     prop_copy_uint8_array (uuid->data, uuid->datalen, buffer, size, offset);
1407
1408   atom_write_size (buffer, size, offset, original_offset);
1409   return *offset - original_offset;
1410 }
1411
1412 guint64
1413 atom_ftyp_copy_data (AtomFTYP * ftyp, guint8 ** buffer, guint64 * size,
1414     guint64 * offset)
1415 {
1416   guint64 original_offset = *offset;
1417
1418   if (!atom_copy_data (&ftyp->header, buffer, size, offset)) {
1419     return 0;
1420   }
1421   prop_copy_fourcc (ftyp->major_brand, buffer, size, offset);
1422   prop_copy_uint32 (ftyp->version, buffer, size, offset);
1423
1424   prop_copy_fourcc_array (ftyp->compatible_brands, ftyp->compatible_brands_size,
1425       buffer, size, offset);
1426
1427   atom_write_size (buffer, size, offset, original_offset);
1428   return *offset - original_offset;
1429 }
1430
1431 guint64
1432 atom_mvhd_copy_data (AtomMVHD * atom, guint8 ** buffer, guint64 * size,
1433     guint64 * offset)
1434 {
1435   guint8 version;
1436   guint64 original_offset = *offset;
1437
1438   if (!atom_full_copy_data (&(atom->header), buffer, size, offset)) {
1439     return 0;
1440   }
1441
1442   version = atom_full_get_version (&(atom->header));
1443   if (version == 0) {
1444     common_time_info_copy_data (&atom->time_info, TRUE, buffer, size, offset);
1445   } else if (version == 1) {
1446     common_time_info_copy_data (&atom->time_info, FALSE, buffer, size, offset);
1447   } else {
1448     *offset = original_offset;
1449     return 0;
1450   }
1451
1452   prop_copy_uint32 (atom->prefered_rate, buffer, size, offset);
1453   prop_copy_uint16 (atom->volume, buffer, size, offset);
1454   prop_copy_uint16 (atom->reserved3, buffer, size, offset);
1455   prop_copy_uint32_array (atom->reserved4, 2, buffer, size, offset);
1456   prop_copy_uint32_array (atom->matrix, 9, buffer, size, offset);
1457   prop_copy_uint32 (atom->preview_time, buffer, size, offset);
1458   prop_copy_uint32 (atom->preview_duration, buffer, size, offset);
1459   prop_copy_uint32 (atom->poster_time, buffer, size, offset);
1460   prop_copy_uint32 (atom->selection_time, buffer, size, offset);
1461   prop_copy_uint32 (atom->selection_duration, buffer, size, offset);
1462   prop_copy_uint32 (atom->current_time, buffer, size, offset);
1463
1464   prop_copy_uint32 (atom->next_track_id, buffer, size, offset);
1465
1466   atom_write_size (buffer, size, offset, original_offset);
1467   return *offset - original_offset;
1468 }
1469
1470 static guint64
1471 atom_tkhd_copy_data (AtomTKHD * tkhd, guint8 ** buffer, guint64 * size,
1472     guint64 * offset)
1473 {
1474   guint64 original_offset = *offset;
1475
1476   if (!atom_full_copy_data (&tkhd->header, buffer, size, offset)) {
1477     return 0;
1478   }
1479
1480   if (atom_full_get_version (&tkhd->header) == 0) {
1481     prop_copy_uint32 ((guint32) tkhd->creation_time, buffer, size, offset);
1482     prop_copy_uint32 ((guint32) tkhd->modification_time, buffer, size, offset);
1483     prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
1484     prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
1485     prop_copy_uint32 ((guint32) tkhd->duration, buffer, size, offset);
1486   } else {
1487     prop_copy_uint64 (tkhd->creation_time, buffer, size, offset);
1488     prop_copy_uint64 (tkhd->modification_time, buffer, size, offset);
1489     prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
1490     prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
1491     prop_copy_uint64 (tkhd->duration, buffer, size, offset);
1492   }
1493
1494   prop_copy_uint32_array (tkhd->reserved2, 2, buffer, size, offset);
1495   prop_copy_uint16 (tkhd->layer, buffer, size, offset);
1496   prop_copy_uint16 (tkhd->alternate_group, buffer, size, offset);
1497   prop_copy_uint16 (tkhd->volume, buffer, size, offset);
1498   prop_copy_uint16 (tkhd->reserved3, buffer, size, offset);
1499   prop_copy_uint32_array (tkhd->matrix, 9, buffer, size, offset);
1500
1501   prop_copy_uint32 (tkhd->width, buffer, size, offset);
1502   prop_copy_uint32 (tkhd->height, buffer, size, offset);
1503
1504   atom_write_size (buffer, size, offset, original_offset);
1505   return *offset - original_offset;
1506 }
1507
1508 static guint64
1509 atom_hdlr_copy_data (AtomHDLR * hdlr, guint8 ** buffer, guint64 * size,
1510     guint64 * offset)
1511 {
1512   guint64 original_offset = *offset;
1513
1514   if (!atom_full_copy_data (&hdlr->header, buffer, size, offset)) {
1515     return 0;
1516   }
1517
1518   prop_copy_fourcc (hdlr->component_type, buffer, size, offset);
1519   prop_copy_fourcc (hdlr->handler_type, buffer, size, offset);
1520   prop_copy_fourcc (hdlr->manufacturer, buffer, size, offset);
1521   prop_copy_uint32 (hdlr->flags, buffer, size, offset);
1522   prop_copy_uint32 (hdlr->flags_mask, buffer, size, offset);
1523
1524   prop_copy_size_string ((guint8 *) hdlr->name, strlen (hdlr->name), buffer,
1525       size, offset);
1526
1527   atom_write_size (buffer, size, offset, original_offset);
1528   return *offset - original_offset;
1529 }
1530
1531 static guint64
1532 atom_vmhd_copy_data (AtomVMHD * vmhd, guint8 ** buffer, guint64 * size,
1533     guint64 * offset)
1534 {
1535   guint64 original_offset = *offset;
1536
1537   if (!atom_full_copy_data (&vmhd->header, buffer, size, offset)) {
1538     return 0;
1539   }
1540   prop_copy_uint16 (vmhd->graphics_mode, buffer, size, offset);
1541   prop_copy_uint16_array (vmhd->opcolor, 3, buffer, size, offset);
1542
1543   atom_write_size (buffer, size, offset, original_offset);
1544   return original_offset - *offset;
1545 }
1546
1547 static guint64
1548 atom_smhd_copy_data (AtomSMHD * smhd, guint8 ** buffer, guint64 * size,
1549     guint64 * offset)
1550 {
1551   guint64 original_offset = *offset;
1552
1553   if (!atom_full_copy_data (&smhd->header, buffer, size, offset)) {
1554     return 0;
1555   }
1556   prop_copy_uint16 (smhd->balance, buffer, size, offset);
1557   prop_copy_uint16 (smhd->reserved, buffer, size, offset);
1558
1559   atom_write_size (buffer, size, offset, original_offset);
1560   return original_offset - *offset;
1561 }
1562
1563 static guint64
1564 atom_hmhd_copy_data (AtomHMHD * hmhd, guint8 ** buffer, guint64 * size,
1565     guint64 * offset)
1566 {
1567   guint64 original_offset = *offset;
1568
1569   if (!atom_full_copy_data (&hmhd->header, buffer, size, offset)) {
1570     return 0;
1571   }
1572   prop_copy_uint16 (hmhd->max_pdu_size, buffer, size, offset);
1573   prop_copy_uint16 (hmhd->avg_pdu_size, buffer, size, offset);
1574   prop_copy_uint32 (hmhd->max_bitrate, buffer, size, offset);
1575   prop_copy_uint32 (hmhd->avg_bitrate, buffer, size, offset);
1576   prop_copy_uint32 (hmhd->sliding_avg_bitrate, buffer, size, offset);
1577
1578   atom_write_size (buffer, size, offset, original_offset);
1579   return original_offset - *offset;
1580 }
1581
1582 static gboolean
1583 atom_url_same_file_flag (AtomURL * url)
1584 {
1585   return (url->header.flags[2] & 0x1) == 1;
1586 }
1587
1588 static guint64
1589 atom_url_copy_data (AtomURL * url, guint8 ** buffer, guint64 * size,
1590     guint64 * offset)
1591 {
1592   guint64 original_offset = *offset;
1593
1594   if (!atom_full_copy_data (&url->header, buffer, size, offset)) {
1595     return 0;
1596   }
1597
1598   if (!atom_url_same_file_flag (url)) {
1599     prop_copy_null_terminated_string (url->location, buffer, size, offset);
1600   }
1601
1602   atom_write_size (buffer, size, offset, original_offset);
1603   return original_offset - *offset;
1604 }
1605
1606 guint64
1607 atom_stts_copy_data (AtomSTTS * stts, guint8 ** buffer, guint64 * size,
1608     guint64 * offset)
1609 {
1610   guint64 original_offset = *offset;
1611   guint i;
1612
1613   if (!atom_full_copy_data (&stts->header, buffer, size, offset)) {
1614     return 0;
1615   }
1616
1617   prop_copy_uint32 (atom_array_get_len (&stts->entries), buffer, size, offset);
1618   /* minimize realloc */
1619   prop_copy_ensure_buffer (buffer, size, offset,
1620       8 * atom_array_get_len (&stts->entries));
1621   for (i = 0; i < atom_array_get_len (&stts->entries); i++) {
1622     STTSEntry *entry = &atom_array_index (&stts->entries, i);
1623
1624     prop_copy_uint32 (entry->sample_count, buffer, size, offset);
1625     prop_copy_int32 (entry->sample_delta, buffer, size, offset);
1626   }
1627
1628   atom_write_size (buffer, size, offset, original_offset);
1629   return *offset - original_offset;
1630 }
1631
1632 static guint64
1633 atom_sample_entry_copy_data (SampleTableEntry * se, guint8 ** buffer,
1634     guint64 * size, guint64 * offset)
1635 {
1636   guint64 original_offset = *offset;
1637
1638   if (!atom_copy_data (&se->header, buffer, size, offset)) {
1639     return 0;
1640   }
1641
1642   prop_copy_uint8_array (se->reserved, 6, buffer, size, offset);
1643   prop_copy_uint16 (se->data_reference_index, buffer, size, offset);
1644
1645   return *offset - original_offset;
1646 }
1647
1648 static guint64
1649 atom_esds_copy_data (AtomESDS * esds, guint8 ** buffer, guint64 * size,
1650     guint64 * offset)
1651 {
1652   guint64 original_offset = *offset;
1653
1654   if (!atom_full_copy_data (&esds->header, buffer, size, offset)) {
1655     return 0;
1656   }
1657   if (!desc_es_descriptor_copy_data (&esds->es, buffer, size, offset)) {
1658     return 0;
1659   }
1660
1661   atom_write_size (buffer, size, offset, original_offset);
1662   return *offset - original_offset;
1663 }
1664
1665 static guint64
1666 atom_frma_copy_data (AtomFRMA * frma, guint8 ** buffer,
1667     guint64 * size, guint64 * offset)
1668 {
1669   guint64 original_offset = *offset;
1670
1671   if (!atom_copy_data (&(frma->header), buffer, size, offset))
1672     return 0;
1673
1674   prop_copy_fourcc (frma->media_type, buffer, size, offset);
1675
1676   atom_write_size (buffer, size, offset, original_offset);
1677   return *offset - original_offset;
1678 }
1679
1680 static guint64
1681 atom_mp4s_copy_data (SampleTableEntryMP4S * mp4s, guint8 ** buffer,
1682     guint64 * size, guint64 * offset)
1683 {
1684   guint64 original_offset = *offset;
1685
1686   if (!atom_sample_entry_copy_data (&mp4s->se, buffer, size, offset)) {
1687     return 0;
1688   }
1689   if (!atom_esds_copy_data (&mp4s->es, buffer, size, offset)) {
1690     return 0;
1691   }
1692
1693   atom_write_size (buffer, size, offset, original_offset);
1694   return *offset - original_offset;
1695 }
1696
1697 static guint64
1698 atom_hint_sample_entry_copy_data (AtomHintSampleEntry * hse, guint8 ** buffer,
1699     guint64 * size, guint64 * offset)
1700 {
1701   guint64 original_offset = *offset;
1702
1703   if (!atom_sample_entry_copy_data (&hse->se, buffer, size, offset)) {
1704     return 0;
1705   }
1706
1707   prop_copy_uint32 (hse->size, buffer, size, offset);
1708   prop_copy_uint8_array (hse->data, hse->size, buffer, size, offset);
1709
1710   atom_write_size (buffer, size, offset, original_offset);
1711   return *offset - original_offset;
1712 }
1713
1714 static guint64
1715 sample_entry_mp4a_copy_data (SampleTableEntryMP4A * mp4a, guint8 ** buffer,
1716     guint64 * size, guint64 * offset)
1717 {
1718   guint64 original_offset = *offset;
1719
1720   if (!atom_sample_entry_copy_data (&mp4a->se, buffer, size, offset)) {
1721     return 0;
1722   }
1723
1724   prop_copy_uint16 (mp4a->version, buffer, size, offset);
1725   prop_copy_uint16 (mp4a->revision_level, buffer, size, offset);
1726   prop_copy_uint32 (mp4a->vendor, buffer, size, offset);
1727   prop_copy_uint16 (mp4a->channels, buffer, size, offset);
1728   prop_copy_uint16 (mp4a->sample_size, buffer, size, offset);
1729   prop_copy_uint16 (mp4a->compression_id, buffer, size, offset);
1730   prop_copy_uint16 (mp4a->packet_size, buffer, size, offset);
1731   prop_copy_uint32 (mp4a->sample_rate, buffer, size, offset);
1732
1733   /* this should always be 0 for mp4 flavor */
1734   if (mp4a->version == 1) {
1735     prop_copy_uint32 (mp4a->samples_per_packet, buffer, size, offset);
1736     prop_copy_uint32 (mp4a->bytes_per_packet, buffer, size, offset);
1737     prop_copy_uint32 (mp4a->bytes_per_frame, buffer, size, offset);
1738     prop_copy_uint32 (mp4a->bytes_per_sample, buffer, size, offset);
1739   }
1740
1741   if (mp4a->extension_atoms) {
1742     if (!atom_info_list_copy_data (mp4a->extension_atoms, buffer, size, offset))
1743       return 0;
1744   }
1745
1746   atom_write_size (buffer, size, offset, original_offset);
1747   return *offset - original_offset;
1748 }
1749
1750 static guint64
1751 sample_entry_mp4v_copy_data (SampleTableEntryMP4V * mp4v, guint8 ** buffer,
1752     guint64 * size, guint64 * offset)
1753 {
1754   guint64 original_offset = *offset;
1755
1756   if (!atom_sample_entry_copy_data (&mp4v->se, buffer, size, offset)) {
1757     return 0;
1758   }
1759
1760   prop_copy_uint16 (mp4v->version, buffer, size, offset);
1761   prop_copy_uint16 (mp4v->revision_level, buffer, size, offset);
1762   prop_copy_fourcc (mp4v->vendor, buffer, size, offset);
1763   prop_copy_uint32 (mp4v->temporal_quality, buffer, size, offset);
1764   prop_copy_uint32 (mp4v->spatial_quality, buffer, size, offset);
1765
1766   prop_copy_uint16 (mp4v->width, buffer, size, offset);
1767   prop_copy_uint16 (mp4v->height, buffer, size, offset);
1768
1769   prop_copy_uint32 (mp4v->horizontal_resolution, buffer, size, offset);
1770   prop_copy_uint32 (mp4v->vertical_resolution, buffer, size, offset);
1771   prop_copy_uint32 (mp4v->datasize, buffer, size, offset);
1772
1773   prop_copy_uint16 (mp4v->frame_count, buffer, size, offset);
1774
1775   prop_copy_fixed_size_string ((guint8 *) mp4v->compressor, 32, buffer, size,
1776       offset);
1777
1778   prop_copy_uint16 (mp4v->depth, buffer, size, offset);
1779   prop_copy_uint16 (mp4v->color_table_id, buffer, size, offset);
1780
1781   /* extra atoms */
1782   if (mp4v->extension_atoms &&
1783       !atom_info_list_copy_data (mp4v->extension_atoms, buffer, size, offset))
1784     return 0;
1785
1786   atom_write_size (buffer, size, offset, original_offset);
1787   return *offset - original_offset;
1788 }
1789
1790 guint64
1791 atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
1792     guint64 * offset)
1793 {
1794   guint64 original_offset = *offset;
1795   guint i;
1796
1797   if (!atom_full_copy_data (&stsz->header, buffer, size, offset)) {
1798     return 0;
1799   }
1800
1801   prop_copy_uint32 (stsz->sample_size, buffer, size, offset);
1802   prop_copy_uint32 (stsz->table_size, buffer, size, offset);
1803   if (stsz->sample_size == 0) {
1804     /* minimize realloc */
1805     prop_copy_ensure_buffer (buffer, size, offset, 4 * stsz->table_size);
1806     /* entry count must match sample count */
1807     g_assert (atom_array_get_len (&stsz->entries) == stsz->table_size);
1808     for (i = 0; i < atom_array_get_len (&stsz->entries); i++) {
1809       prop_copy_uint32 (atom_array_index (&stsz->entries, i), buffer, size,
1810           offset);
1811     }
1812   }
1813
1814   atom_write_size (buffer, size, offset, original_offset);
1815   return *offset - original_offset;
1816 }
1817
1818 guint64
1819 atom_stsc_copy_data (AtomSTSC * stsc, guint8 ** buffer, guint64 * size,
1820     guint64 * offset)
1821 {
1822   guint64 original_offset = *offset;
1823   guint i;
1824
1825   if (!atom_full_copy_data (&stsc->header, buffer, size, offset)) {
1826     return 0;
1827   }
1828
1829   prop_copy_uint32 (atom_array_get_len (&stsc->entries), buffer, size, offset);
1830   /* minimize realloc */
1831   prop_copy_ensure_buffer (buffer, size, offset,
1832       12 * atom_array_get_len (&stsc->entries));
1833
1834   for (i = 0; i < atom_array_get_len (&stsc->entries); i++) {
1835     STSCEntry *entry = &atom_array_index (&stsc->entries, i);
1836
1837     prop_copy_uint32 (entry->first_chunk, buffer, size, offset);
1838     prop_copy_uint32 (entry->samples_per_chunk, buffer, size, offset);
1839     prop_copy_uint32 (entry->sample_description_index, buffer, size, offset);
1840   }
1841
1842   atom_write_size (buffer, size, offset, original_offset);
1843   return *offset - original_offset;
1844 }
1845
1846 guint64
1847 atom_ctts_copy_data (AtomCTTS * ctts, guint8 ** buffer, guint64 * size,
1848     guint64 * offset)
1849 {
1850   guint64 original_offset = *offset;
1851   guint i;
1852
1853   if (!atom_full_copy_data (&ctts->header, buffer, size, offset)) {
1854     return 0;
1855   }
1856
1857   prop_copy_uint32 (atom_array_get_len (&ctts->entries), buffer, size, offset);
1858   /* minimize realloc */
1859   prop_copy_ensure_buffer (buffer, size, offset,
1860       8 * atom_array_get_len (&ctts->entries));
1861   for (i = 0; i < atom_array_get_len (&ctts->entries); i++) {
1862     CTTSEntry *entry = &atom_array_index (&ctts->entries, i);
1863
1864     prop_copy_uint32 (entry->samplecount, buffer, size, offset);
1865     prop_copy_uint32 (entry->sampleoffset, buffer, size, offset);
1866   }
1867
1868   atom_write_size (buffer, size, offset, original_offset);
1869   return *offset - original_offset;
1870 }
1871
1872 guint64
1873 atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size,
1874     guint64 * offset)
1875 {
1876   guint64 original_offset = *offset;
1877   guint i;
1878   gboolean trunc_to_32 = stco64->header.header.type == FOURCC_stco;
1879
1880   if (!atom_full_copy_data (&stco64->header, buffer, size, offset)) {
1881     return 0;
1882   }
1883
1884   prop_copy_uint32 (atom_array_get_len (&stco64->entries), buffer, size,
1885       offset);
1886
1887   /* minimize realloc */
1888   prop_copy_ensure_buffer (buffer, size, offset,
1889       8 * atom_array_get_len (&stco64->entries));
1890   for (i = 0; i < atom_array_get_len (&stco64->entries); i++) {
1891     guint64 *value = &atom_array_index (&stco64->entries, i);
1892
1893     if (trunc_to_32) {
1894       prop_copy_uint32 ((guint32) * value, buffer, size, offset);
1895     } else {
1896       prop_copy_uint64 (*value, buffer, size, offset);
1897     }
1898   }
1899
1900   atom_write_size (buffer, size, offset, original_offset);
1901   return *offset - original_offset;
1902 }
1903
1904 guint64
1905 atom_stss_copy_data (AtomSTSS * stss, guint8 ** buffer, guint64 * size,
1906     guint64 * offset)
1907 {
1908   guint64 original_offset = *offset;
1909   guint i;
1910
1911   if (atom_array_get_len (&stss->entries) == 0) {
1912     /* FIXME not needing this atom might be confused with error while copying */
1913     return 0;
1914   }
1915
1916   if (!atom_full_copy_data (&stss->header, buffer, size, offset)) {
1917     return 0;
1918   }
1919
1920   prop_copy_uint32 (atom_array_get_len (&stss->entries), buffer, size, offset);
1921   /* minimize realloc */
1922   prop_copy_ensure_buffer (buffer, size, offset,
1923       4 * atom_array_get_len (&stss->entries));
1924   for (i = 0; i < atom_array_get_len (&stss->entries); i++) {
1925     prop_copy_uint32 (atom_array_index (&stss->entries, i), buffer, size,
1926         offset);
1927   }
1928
1929   atom_write_size (buffer, size, offset, original_offset);
1930   return *offset - original_offset;
1931 }
1932
1933 static guint64
1934 atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size,
1935     guint64 * offset)
1936 {
1937   guint64 original_offset = *offset;
1938   GList *walker;
1939
1940   if (!atom_full_copy_data (&stsd->header, buffer, size, offset)) {
1941     return 0;
1942   }
1943
1944   prop_copy_uint32 (stsd->n_entries, buffer, size, offset);
1945
1946   for (walker = g_list_last (stsd->entries); walker != NULL;
1947       walker = g_list_previous (walker)) {
1948     SampleTableEntry *se = (SampleTableEntry *) walker->data;
1949
1950     switch (((Atom *) walker->data)->type) {
1951       case FOURCC_mp4a:
1952         if (!sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) walker->data,
1953                 buffer, size, offset)) {
1954           return 0;
1955         }
1956         break;
1957       case FOURCC_mp4s:
1958         if (!atom_mp4s_copy_data ((SampleTableEntryMP4S *) walker->data,
1959                 buffer, size, offset)) {
1960           return 0;
1961         }
1962         break;
1963       case FOURCC_mp4v:
1964         if (!sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) walker->data,
1965                 buffer, size, offset)) {
1966           return 0;
1967         }
1968         break;
1969       default:
1970         if (se->kind == VIDEO) {
1971           if (!sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *)
1972                   walker->data, buffer, size, offset)) {
1973             return 0;
1974           }
1975         } else if (se->kind == AUDIO) {
1976           if (!sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *)
1977                   walker->data, buffer, size, offset)) {
1978             return 0;
1979           }
1980         } else {
1981           if (!atom_hint_sample_entry_copy_data (
1982                   (AtomHintSampleEntry *) walker->data, buffer, size, offset)) {
1983             return 0;
1984           }
1985         }
1986         break;
1987     }
1988   }
1989
1990   atom_write_size (buffer, size, offset, original_offset);
1991   return *offset - original_offset;
1992 }
1993
1994 static guint64
1995 atom_stbl_copy_data (AtomSTBL * stbl, guint8 ** buffer, guint64 * size,
1996     guint64 * offset)
1997 {
1998   guint64 original_offset = *offset;
1999
2000   if (!atom_copy_data (&stbl->header, buffer, size, offset)) {
2001     return 0;
2002   }
2003
2004   if (!atom_stsd_copy_data (&stbl->stsd, buffer, size, offset)) {
2005     return 0;
2006   }
2007   if (!atom_stts_copy_data (&stbl->stts, buffer, size, offset)) {
2008     return 0;
2009   }
2010   /* this atom is optional, so let's check if we need it
2011    * (to avoid false error) */
2012   if (atom_array_get_len (&stbl->stss.entries)) {
2013     if (!atom_stss_copy_data (&stbl->stss, buffer, size, offset)) {
2014       return 0;
2015     }
2016   }
2017
2018   if (!atom_stsc_copy_data (&stbl->stsc, buffer, size, offset)) {
2019     return 0;
2020   }
2021   if (!atom_stsz_copy_data (&stbl->stsz, buffer, size, offset)) {
2022     return 0;
2023   }
2024   if (stbl->ctts && stbl->ctts->do_pts) {
2025     if (!atom_ctts_copy_data (stbl->ctts, buffer, size, offset)) {
2026       return 0;
2027     }
2028   }
2029   if (!atom_stco64_copy_data (&stbl->stco64, buffer, size, offset)) {
2030     return 0;
2031   }
2032
2033   atom_write_size (buffer, size, offset, original_offset);
2034   return original_offset - *offset;
2035 }
2036
2037
2038 static guint64
2039 atom_dref_copy_data (AtomDREF * dref, guint8 ** buffer, guint64 * size,
2040     guint64 * offset)
2041 {
2042   guint64 original_offset = *offset;
2043   GList *walker;
2044
2045   if (!atom_full_copy_data (&dref->header, buffer, size, offset)) {
2046     return 0;
2047   }
2048
2049   prop_copy_uint32 (g_list_length (dref->entries), buffer, size, offset);
2050
2051   walker = dref->entries;
2052   while (walker != NULL) {
2053     Atom *atom = (Atom *) walker->data;
2054
2055     if (atom->type == FOURCC_url_) {
2056       atom_url_copy_data ((AtomURL *) atom, buffer, size, offset);
2057     } else if (atom->type == FOURCC_alis) {
2058       atom_full_copy_data ((AtomFull *) atom, buffer, size, offset);
2059     } else {
2060       g_error ("Unsupported atom used inside dref atom");
2061     }
2062     walker = g_list_next (walker);
2063   }
2064
2065   atom_write_size (buffer, size, offset, original_offset);
2066   return *offset - original_offset;
2067 }
2068
2069 static guint64
2070 atom_dinf_copy_data (AtomDINF * dinf, guint8 ** buffer, guint64 * size,
2071     guint64 * offset)
2072 {
2073   guint64 original_offset = *offset;
2074
2075   if (!atom_copy_data (&dinf->header, buffer, size, offset)) {
2076     return 0;
2077   }
2078
2079   if (!atom_dref_copy_data (&dinf->dref, buffer, size, offset)) {
2080     return 0;
2081   }
2082
2083   atom_write_size (buffer, size, offset, original_offset);
2084   return original_offset - *offset;
2085 }
2086
2087 static guint64
2088 atom_minf_copy_data (AtomMINF * minf, guint8 ** buffer, guint64 * size,
2089     guint64 * offset)
2090 {
2091   guint64 original_offset = *offset;
2092
2093   if (!atom_copy_data (&minf->header, buffer, size, offset)) {
2094     return 0;
2095   }
2096
2097   if (minf->vmhd) {
2098     if (!atom_vmhd_copy_data (minf->vmhd, buffer, size, offset)) {
2099       return 0;
2100     }
2101   } else if (minf->smhd) {
2102     if (!atom_smhd_copy_data (minf->smhd, buffer, size, offset)) {
2103       return 0;
2104     }
2105   } else if (minf->hmhd) {
2106     if (!atom_hmhd_copy_data (minf->hmhd, buffer, size, offset)) {
2107       return 0;
2108     }
2109   }
2110
2111   if (minf->hdlr) {
2112     if (!atom_hdlr_copy_data (minf->hdlr, buffer, size, offset)) {
2113       return 0;
2114     }
2115   }
2116
2117   if (!atom_dinf_copy_data (&minf->dinf, buffer, size, offset)) {
2118     return 0;
2119   }
2120   if (!atom_stbl_copy_data (&minf->stbl, buffer, size, offset)) {
2121     return 0;
2122   }
2123
2124   atom_write_size (buffer, size, offset, original_offset);
2125   return *offset - original_offset;
2126 }
2127
2128 static guint64
2129 atom_mdhd_copy_data (AtomMDHD * mdhd, guint8 ** buffer, guint64 * size,
2130     guint64 * offset)
2131 {
2132   guint64 original_offset = *offset;
2133
2134   if (!atom_full_copy_data (&mdhd->header, buffer, size, offset)) {
2135     return 0;
2136   }
2137
2138   if (!common_time_info_copy_data (&mdhd->time_info,
2139           atom_full_get_version (&mdhd->header) == 0, buffer, size, offset)) {
2140     return 0;
2141   }
2142
2143   prop_copy_uint16 (mdhd->language_code, buffer, size, offset);
2144   prop_copy_uint16 (mdhd->quality, buffer, size, offset);
2145
2146   atom_write_size (buffer, size, offset, original_offset);
2147   return *offset - original_offset;
2148 }
2149
2150 static guint64
2151 atom_mdia_copy_data (AtomMDIA * mdia, guint8 ** buffer, guint64 * size,
2152     guint64 * offset)
2153 {
2154   guint64 original_offset = *offset;
2155
2156   if (!atom_copy_data (&mdia->header, buffer, size, offset)) {
2157     return 0;
2158   }
2159   if (!atom_mdhd_copy_data (&mdia->mdhd, buffer, size, offset)) {
2160     return 0;
2161   }
2162   if (!atom_hdlr_copy_data (&mdia->hdlr, buffer, size, offset)) {
2163     return 0;
2164   }
2165
2166   if (!atom_minf_copy_data (&mdia->minf, buffer, size, offset)) {
2167     return 0;
2168   }
2169
2170   atom_write_size (buffer, size, offset, original_offset);
2171   return *offset - original_offset;
2172 }
2173
2174 static guint64
2175 atom_elst_copy_data (AtomELST * elst, guint8 ** buffer, guint64 * size,
2176     guint64 * offset)
2177 {
2178   guint64 original_offset = *offset;
2179   GSList *walker;
2180
2181   if (!atom_full_copy_data (&elst->header, buffer, size, offset)) {
2182     return 0;
2183   }
2184
2185   prop_copy_uint32 (g_slist_length (elst->entries), buffer, size, offset);
2186
2187   for (walker = elst->entries; walker != NULL; walker = g_slist_next (walker)) {
2188     EditListEntry *entry = (EditListEntry *) walker->data;
2189     prop_copy_uint32 (entry->duration, buffer, size, offset);
2190     prop_copy_uint32 (entry->media_time, buffer, size, offset);
2191     prop_copy_uint32 (entry->media_rate, buffer, size, offset);
2192   }
2193   atom_write_size (buffer, size, offset, original_offset);
2194   return *offset - original_offset;
2195 }
2196
2197 static guint64
2198 atom_edts_copy_data (AtomEDTS * edts, guint8 ** buffer, guint64 * size,
2199     guint64 * offset)
2200 {
2201   guint64 original_offset = *offset;
2202
2203   if (!atom_copy_data (&(edts->header), buffer, size, offset))
2204     return 0;
2205
2206   if (!atom_elst_copy_data (&(edts->elst), buffer, size, offset))
2207     return 0;
2208
2209   atom_write_size (buffer, size, offset, original_offset);
2210   return *offset - original_offset;
2211 }
2212
2213 guint64
2214 atom_trak_copy_data (AtomTRAK * trak, guint8 ** buffer, guint64 * size,
2215     guint64 * offset)
2216 {
2217   guint64 original_offset = *offset;
2218
2219   if (!atom_copy_data (&trak->header, buffer, size, offset)) {
2220     return 0;
2221   }
2222   if (!atom_tkhd_copy_data (&trak->tkhd, buffer, size, offset)) {
2223     return 0;
2224   }
2225   if (trak->edts) {
2226     if (!atom_edts_copy_data (trak->edts, buffer, size, offset)) {
2227       return 0;
2228     }
2229   }
2230
2231   if (!atom_mdia_copy_data (&trak->mdia, buffer, size, offset)) {
2232     return 0;
2233   }
2234
2235   atom_write_size (buffer, size, offset, original_offset);
2236   return *offset - original_offset;
2237 }
2238
2239 static guint64
2240 atom_tag_data_copy_data (AtomTagData * data, guint8 ** buffer, guint64 * size,
2241     guint64 * offset)
2242 {
2243   guint64 original_offset = *offset;
2244
2245   if (!atom_full_copy_data (&data->header, buffer, size, offset)) {
2246     return 0;
2247   }
2248
2249   prop_copy_uint32 (data->reserved, buffer, size, offset);
2250   prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
2251
2252   atom_write_size (buffer, size, offset, original_offset);
2253   return *offset - original_offset;
2254 }
2255
2256 static guint64
2257 atom_tag_copy_data (AtomTag * tag, guint8 ** buffer, guint64 * size,
2258     guint64 * offset)
2259 {
2260   guint64 original_offset = *offset;
2261
2262   if (!atom_copy_data (&tag->header, buffer, size, offset)) {
2263     return 0;
2264   }
2265
2266   if (!atom_tag_data_copy_data (&tag->data, buffer, size, offset)) {
2267     return 0;
2268   }
2269
2270   atom_write_size (buffer, size, offset, original_offset);
2271   return *offset - original_offset;
2272 }
2273
2274 static guint64
2275 atom_ilst_copy_data (AtomILST * ilst, guint8 ** buffer, guint64 * size,
2276     guint64 * offset)
2277 {
2278   guint64 original_offset = *offset;
2279
2280   if (!atom_copy_data (&ilst->header, buffer, size, offset)) {
2281     return 0;
2282   }
2283   /* extra atoms */
2284   if (ilst->entries &&
2285       !atom_info_list_copy_data (ilst->entries, buffer, size, offset))
2286     return 0;
2287
2288   atom_write_size (buffer, size, offset, original_offset);
2289   return *offset - original_offset;
2290 }
2291
2292 static guint64
2293 atom_meta_copy_data (AtomMETA * meta, guint8 ** buffer, guint64 * size,
2294     guint64 * offset)
2295 {
2296   guint64 original_offset = *offset;
2297
2298   if (!atom_full_copy_data (&meta->header, buffer, size, offset)) {
2299     return 0;
2300   }
2301   if (!atom_hdlr_copy_data (&meta->hdlr, buffer, size, offset)) {
2302     return 0;
2303   }
2304   if (meta->ilst) {
2305     if (!atom_ilst_copy_data (meta->ilst, buffer, size, offset)) {
2306       return 0;
2307     }
2308   }
2309
2310   atom_write_size (buffer, size, offset, original_offset);
2311   return *offset - original_offset;
2312 }
2313
2314 static guint64
2315 atom_udta_copy_data (AtomUDTA * udta, guint8 ** buffer, guint64 * size,
2316     guint64 * offset)
2317 {
2318   guint64 original_offset = *offset;
2319
2320   if (!atom_copy_data (&udta->header, buffer, size, offset)) {
2321     return 0;
2322   }
2323   if (udta->meta) {
2324     if (!atom_meta_copy_data (udta->meta, buffer, size, offset)) {
2325       return 0;
2326     }
2327   }
2328   if (udta->entries) {
2329     /* extra atoms */
2330     if (!atom_info_list_copy_data (udta->entries, buffer, size, offset))
2331       return 0;
2332   }
2333
2334   atom_write_size (buffer, size, offset, original_offset);
2335   return *offset - original_offset;
2336 }
2337
2338 static guint64
2339 atom_mehd_copy_data (AtomMEHD * mehd, guint8 ** buffer, guint64 * size,
2340     guint64 * offset)
2341 {
2342   guint64 original_offset = *offset;
2343
2344   if (!atom_full_copy_data (&mehd->header, buffer, size, offset)) {
2345     return 0;
2346   }
2347
2348   prop_copy_uint64 (mehd->fragment_duration, buffer, size, offset);
2349
2350   atom_write_size (buffer, size, offset, original_offset);
2351   return *offset - original_offset;
2352 }
2353
2354 static guint64
2355 atom_trex_copy_data (AtomTREX * trex, guint8 ** buffer, guint64 * size,
2356     guint64 * offset)
2357 {
2358   guint64 original_offset = *offset;
2359
2360   if (!atom_full_copy_data (&trex->header, buffer, size, offset)) {
2361     return 0;
2362   }
2363
2364   prop_copy_uint32 (trex->track_ID, buffer, size, offset);
2365   prop_copy_uint32 (trex->default_sample_description_index, buffer, size,
2366       offset);
2367   prop_copy_uint32 (trex->default_sample_duration, buffer, size, offset);
2368   prop_copy_uint32 (trex->default_sample_size, buffer, size, offset);
2369   prop_copy_uint32 (trex->default_sample_flags, buffer, size, offset);
2370
2371   atom_write_size (buffer, size, offset, original_offset);
2372   return *offset - original_offset;
2373 }
2374
2375 static guint64
2376 atom_mvex_copy_data (AtomMVEX * mvex, guint8 ** buffer, guint64 * size,
2377     guint64 * offset)
2378 {
2379   guint64 original_offset = *offset;
2380   GList *walker;
2381
2382   if (!atom_copy_data (&mvex->header, buffer, size, offset)) {
2383     return 0;
2384   }
2385
2386   if (!atom_mehd_copy_data (&mvex->mehd, buffer, size, offset)) {
2387     return 0;
2388   }
2389
2390   walker = g_list_first (mvex->trexs);
2391   while (walker != NULL) {
2392     if (!atom_trex_copy_data ((AtomTREX *) walker->data, buffer, size, offset)) {
2393       return 0;
2394     }
2395     walker = g_list_next (walker);
2396   }
2397
2398   atom_write_size (buffer, size, offset, original_offset);
2399   return *offset - original_offset;
2400 }
2401
2402 guint64
2403 atom_moov_copy_data (AtomMOOV * atom, guint8 ** buffer, guint64 * size,
2404     guint64 * offset)
2405 {
2406   guint64 original_offset = *offset;
2407   GList *walker;
2408
2409   if (!atom_copy_data (&(atom->header), buffer, size, offset))
2410     return 0;
2411
2412   if (!atom_mvhd_copy_data (&(atom->mvhd), buffer, size, offset))
2413     return 0;
2414
2415   walker = g_list_first (atom->traks);
2416   while (walker != NULL) {
2417     if (!atom_trak_copy_data ((AtomTRAK *) walker->data, buffer, size, offset)) {
2418       return 0;
2419     }
2420     walker = g_list_next (walker);
2421   }
2422
2423   if (atom->udta) {
2424     if (!atom_udta_copy_data (atom->udta, buffer, size, offset)) {
2425       return 0;
2426     }
2427   }
2428
2429   if (atom->fragmented) {
2430     if (!atom_mvex_copy_data (&atom->mvex, buffer, size, offset)) {
2431       return 0;
2432     }
2433   }
2434
2435   atom_write_size (buffer, size, offset, original_offset);
2436   return *offset - original_offset;
2437 }
2438
2439 static guint64
2440 atom_wave_copy_data (AtomWAVE * wave, guint8 ** buffer,
2441     guint64 * size, guint64 * offset)
2442 {
2443   guint64 original_offset = *offset;
2444
2445   if (!atom_copy_data (&(wave->header), buffer, size, offset))
2446     return 0;
2447
2448   if (wave->extension_atoms) {
2449     if (!atom_info_list_copy_data (wave->extension_atoms, buffer, size, offset))
2450       return 0;
2451   }
2452
2453   atom_write_size (buffer, size, offset, original_offset);
2454   return *offset - original_offset;
2455 }
2456
2457 /* -- end of copy data functions -- */
2458
2459 /* -- general functions, API and support functions */
2460
2461 /* add samples to tables */
2462
2463 static void
2464 atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
2465 {
2466   STSCEntry nentry;
2467   gint len;
2468
2469   if ((len = atom_array_get_len (&stsc->entries)) &&
2470       ((atom_array_index (&stsc->entries, len - 1)).samples_per_chunk ==
2471           nsamples))
2472     return;
2473
2474   nentry.first_chunk = first_chunk;
2475   nentry.samples_per_chunk = nsamples;
2476   nentry.sample_description_index = 1;
2477   atom_array_append (&stsc->entries, nentry, 128);
2478 }
2479
2480 static void
2481 atom_stts_add_entry (AtomSTTS * stts, guint32 sample_count, gint32 sample_delta)
2482 {
2483   STTSEntry *entry = NULL;
2484
2485   if (G_LIKELY (atom_array_get_len (&stts->entries) != 0))
2486     entry = &atom_array_index (&stts->entries,
2487         atom_array_get_len (&stts->entries) - 1);
2488
2489   if (entry && entry->sample_delta == sample_delta) {
2490     entry->sample_count += sample_count;
2491   } else {
2492     STTSEntry nentry;
2493
2494     nentry.sample_count = sample_count;
2495     nentry.sample_delta = sample_delta;
2496     atom_array_append (&stts->entries, nentry, 256);
2497   }
2498 }
2499
2500 static void
2501 atom_stsz_add_entry (AtomSTSZ * stsz, guint32 nsamples, guint32 size)
2502 {
2503   guint32 i;
2504
2505   stsz->table_size += nsamples;
2506   if (stsz->sample_size != 0) {
2507     /* it is constant size, we don't need entries */
2508     return;
2509   }
2510   for (i = 0; i < nsamples; i++) {
2511     atom_array_append (&stsz->entries, size, 1024);
2512   }
2513 }
2514
2515 static guint32
2516 atom_stco64_get_entry_count (AtomSTCO64 * stco64)
2517 {
2518   return atom_array_get_len (&stco64->entries);
2519 }
2520
2521 static void
2522 atom_stco64_add_entry (AtomSTCO64 * stco64, guint64 entry)
2523 {
2524   atom_array_append (&stco64->entries, entry, 256);
2525   if (entry > G_MAXUINT32)
2526     stco64->header.header.type = FOURCC_co64;
2527 }
2528
2529 static void
2530 atom_stss_add_entry (AtomSTSS * stss, guint32 sample)
2531 {
2532   atom_array_append (&stss->entries, sample, 512);
2533 }
2534
2535 static void
2536 atom_stbl_add_stss_entry (AtomSTBL * stbl)
2537 {
2538   guint32 sample_index = stbl->stsz.table_size;
2539
2540   atom_stss_add_entry (&stbl->stss, sample_index);
2541 }
2542
2543 static void
2544 atom_ctts_add_entry (AtomCTTS * ctts, guint32 nsamples, guint32 offset)
2545 {
2546   CTTSEntry *entry = NULL;
2547
2548   if (G_LIKELY (atom_array_get_len (&ctts->entries) != 0))
2549     entry = &atom_array_index (&ctts->entries,
2550         atom_array_get_len (&ctts->entries) - 1);
2551
2552   if (entry == NULL || entry->sampleoffset != offset) {
2553     CTTSEntry nentry;
2554
2555     nentry.samplecount = nsamples;
2556     nentry.sampleoffset = offset;
2557     atom_array_append (&ctts->entries, nentry, 256);
2558     if (offset != 0)
2559       ctts->do_pts = TRUE;
2560   } else {
2561     entry->samplecount += nsamples;
2562   }
2563 }
2564
2565 static void
2566 atom_stbl_add_ctts_entry (AtomSTBL * stbl, guint32 nsamples, guint32 offset)
2567 {
2568   if (stbl->ctts == NULL) {
2569     stbl->ctts = atom_ctts_new ();
2570   }
2571   atom_ctts_add_entry (stbl->ctts, nsamples, offset);
2572 }
2573
2574 void
2575 atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta,
2576     guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset)
2577 {
2578   atom_stts_add_entry (&stbl->stts, nsamples, delta);
2579   atom_stsz_add_entry (&stbl->stsz, nsamples, size);
2580   atom_stco64_add_entry (&stbl->stco64, chunk_offset);
2581   atom_stsc_add_new_entry (&stbl->stsc,
2582       atom_stco64_get_entry_count (&stbl->stco64), nsamples);
2583   if (sync)
2584     atom_stbl_add_stss_entry (stbl);
2585   /* always store to arrange for consistent content */
2586   atom_stbl_add_ctts_entry (stbl, nsamples, pts_offset);
2587 }
2588
2589 void
2590 atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta,
2591     guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset)
2592 {
2593   AtomSTBL *stbl = &trak->mdia.minf.stbl;
2594   atom_stbl_add_samples (stbl, nsamples, delta, size, chunk_offset, sync,
2595       pts_offset);
2596 }
2597
2598 /* trak and moov molding */
2599
2600 guint32
2601 atom_trak_get_timescale (AtomTRAK * trak)
2602 {
2603   return trak->mdia.mdhd.time_info.timescale;
2604 }
2605
2606 guint32
2607 atom_trak_get_id (AtomTRAK * trak)
2608 {
2609   return trak->tkhd.track_ID;
2610 }
2611
2612 static void
2613 atom_trak_set_id (AtomTRAK * trak, guint32 id)
2614 {
2615   trak->tkhd.track_ID = id;
2616 }
2617
2618 static void
2619 atom_moov_add_trex (AtomMOOV * moov, AtomTREX * trex)
2620 {
2621   moov->mvex.trexs = g_list_append (moov->mvex.trexs, trex);
2622 }
2623
2624 static AtomTREX *
2625 atom_trex_new (AtomTRAK * trak)
2626 {
2627   guint8 flags[3] = { 0, 0, 0 };
2628   AtomTREX *trex = g_new0 (AtomTREX, 1);
2629
2630   atom_full_init (&trex->header, FOURCC_trex, 0, 0, 0, flags);
2631
2632   trex->track_ID = trak->tkhd.track_ID;
2633   trex->default_sample_description_index = 1;
2634   trex->default_sample_duration = 0;
2635   trex->default_sample_size = 0;
2636   trex->default_sample_flags = 0;
2637
2638   return trex;
2639 }
2640
2641 void
2642 atom_moov_add_trak (AtomMOOV * moov, AtomTRAK * trak)
2643 {
2644   atom_trak_set_id (trak, moov->mvhd.next_track_id++);
2645   moov->traks = g_list_append (moov->traks, trak);
2646   /* additional trak means also new trex */
2647   atom_moov_add_trex (moov, atom_trex_new (trak));
2648 }
2649
2650 static guint64
2651 atom_trak_get_duration (AtomTRAK * trak)
2652 {
2653   return trak->tkhd.duration;
2654 }
2655
2656 static guint64
2657 atom_stts_get_total_duration (AtomSTTS * stts)
2658 {
2659   guint i;
2660   guint64 sum = 0;
2661
2662   for (i = 0; i < atom_array_get_len (&stts->entries); i++) {
2663     STTSEntry *entry = &atom_array_index (&stts->entries, i);
2664
2665     sum += (guint64) (entry->sample_count) * entry->sample_delta;
2666   }
2667   return sum;
2668 }
2669
2670 static void
2671 atom_trak_update_duration (AtomTRAK * trak, guint64 moov_timescale)
2672 {
2673   trak->mdia.mdhd.time_info.duration =
2674       atom_stts_get_total_duration (&trak->mdia.minf.stbl.stts);
2675   if (trak->mdia.mdhd.time_info.timescale != 0) {
2676     trak->tkhd.duration =
2677         gst_util_uint64_scale (trak->mdia.mdhd.time_info.duration,
2678         moov_timescale, trak->mdia.mdhd.time_info.timescale);
2679   } else {
2680     trak->tkhd.duration = 0;
2681   }
2682 }
2683
2684 static guint32
2685 atom_moov_get_timescale (AtomMOOV * moov)
2686 {
2687   return moov->mvhd.time_info.timescale;
2688 }
2689
2690 void
2691 atom_moov_update_timescale (AtomMOOV * moov, guint32 timescale)
2692 {
2693   moov->mvhd.time_info.timescale = timescale;
2694 }
2695
2696 void
2697 atom_moov_update_duration (AtomMOOV * moov)
2698 {
2699   GList *traks = moov->traks;
2700   guint64 dur, duration = 0;
2701
2702   while (traks) {
2703     AtomTRAK *trak = (AtomTRAK *) traks->data;
2704
2705     atom_trak_update_duration (trak, atom_moov_get_timescale (moov));
2706     dur = atom_trak_get_duration (trak);
2707     if (dur > duration)
2708       duration = dur;
2709     traks = g_list_next (traks);
2710   }
2711   moov->mvhd.time_info.duration = duration;
2712   moov->mvex.mehd.fragment_duration = duration;
2713 }
2714
2715 void
2716 atom_moov_set_fragmented (AtomMOOV * moov, gboolean fragmented)
2717 {
2718   moov->fragmented = fragmented;
2719 }
2720
2721 void
2722 atom_stco64_chunks_add_offset (AtomSTCO64 * stco64, guint32 offset)
2723 {
2724   guint i;
2725
2726   for (i = 0; i < atom_array_get_len (&stco64->entries); i++) {
2727     guint64 *value = &atom_array_index (&stco64->entries, i);
2728
2729     *value += offset;
2730   }
2731 }
2732
2733 void
2734 atom_moov_chunks_add_offset (AtomMOOV * moov, guint32 offset)
2735 {
2736   GList *traks = moov->traks;
2737
2738   while (traks) {
2739     AtomTRAK *trak = (AtomTRAK *) traks->data;
2740
2741     atom_stco64_chunks_add_offset (&trak->mdia.minf.stbl.stco64, offset);
2742     traks = g_list_next (traks);
2743   }
2744 }
2745
2746 void
2747 atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate,
2748     guint32 max_bitrate)
2749 {
2750   AtomESDS *esds = NULL;
2751   AtomData *btrt = NULL;
2752   AtomWAVE *wave = NULL;
2753   AtomSTSD *stsd;
2754   GList *iter;
2755   GList *extensioniter = NULL;
2756
2757   g_return_if_fail (trak != NULL);
2758
2759   if (avg_bitrate == 0 && max_bitrate == 0)
2760     return;
2761
2762   stsd = &trak->mdia.minf.stbl.stsd;
2763   for (iter = stsd->entries; iter; iter = g_list_next (iter)) {
2764     SampleTableEntry *entry = iter->data;
2765
2766     switch (entry->kind) {
2767       case AUDIO:{
2768         SampleTableEntryMP4A *audioentry = (SampleTableEntryMP4A *) entry;
2769         extensioniter = audioentry->extension_atoms;
2770         break;
2771       }
2772       case VIDEO:{
2773         SampleTableEntryMP4V *videoentry = (SampleTableEntryMP4V *) entry;
2774         extensioniter = videoentry->extension_atoms;
2775         break;
2776       }
2777       default:
2778         break;
2779     }
2780   }
2781
2782   for (; extensioniter; extensioniter = g_list_next (extensioniter)) {
2783     AtomInfo *atominfo = extensioniter->data;
2784     if (atominfo->atom->type == FOURCC_esds) {
2785       esds = (AtomESDS *) atominfo->atom;
2786     } else if (atominfo->atom->type == FOURCC_btrt) {
2787       btrt = (AtomData *) atominfo->atom;
2788     } else if (atominfo->atom->type == FOURCC_wave) {
2789       wave = (AtomWAVE *) atominfo->atom;
2790     }
2791   }
2792
2793   /* wave might have an esds internally */
2794   if (wave) {
2795     for (extensioniter = wave->extension_atoms; extensioniter;
2796         extensioniter = g_list_next (extensioniter)) {
2797       AtomInfo *atominfo = extensioniter->data;
2798       if (atominfo->atom->type == FOURCC_esds) {
2799         esds = (AtomESDS *) atominfo->atom;
2800         break;
2801       }
2802     }
2803   }
2804
2805   if (esds) {
2806     if (avg_bitrate && esds->es.dec_conf_desc.avg_bitrate == 0)
2807       esds->es.dec_conf_desc.avg_bitrate = avg_bitrate;
2808     if (max_bitrate && esds->es.dec_conf_desc.max_bitrate == 0)
2809       esds->es.dec_conf_desc.max_bitrate = max_bitrate;
2810   }
2811   if (btrt) {
2812     /* type(4bytes) + size(4bytes) + buffersize(4bytes) +
2813      * maxbitrate(bytes) + avgbitrate(bytes) */
2814     if (max_bitrate && GST_READ_UINT32_BE (btrt->data + 4) == 0)
2815       GST_WRITE_UINT32_BE (btrt->data + 4, max_bitrate);
2816     if (avg_bitrate && GST_READ_UINT32_BE (btrt->data + 8) == 0)
2817       GST_WRITE_UINT32_BE (btrt->data + 8, avg_bitrate);
2818   }
2819 }
2820
2821 /*
2822  * Meta tags functions
2823  */
2824 static void
2825 atom_moov_init_metatags (AtomMOOV * moov, AtomsContext * context)
2826 {
2827   if (!moov->udta) {
2828     moov->udta = atom_udta_new ();
2829   }
2830   if (context->flavor != ATOMS_TREE_FLAVOR_3GP) {
2831     if (!moov->udta->meta) {
2832       moov->udta->meta = atom_meta_new ();
2833     }
2834     if (!moov->udta->meta->ilst) {
2835       moov->udta->meta->ilst = atom_ilst_new ();
2836     }
2837   }
2838 }
2839
2840 static void
2841 atom_tag_data_alloc_data (AtomTagData * data, guint size)
2842 {
2843   if (data->data != NULL) {
2844     g_free (data->data);
2845   }
2846   data->data = g_new0 (guint8, size);
2847   data->datalen = size;
2848 }
2849
2850 static void
2851 atom_moov_append_tag (AtomMOOV * moov, AtomInfo * tag)
2852 {
2853   GList **entries;
2854
2855   atom_moov_init_metatags (moov, &moov->context);
2856   if (moov->udta->meta)
2857     entries = &moov->udta->meta->ilst->entries;
2858   else
2859     entries = &moov->udta->entries;
2860   *entries = g_list_append (*entries, tag);
2861 }
2862
2863 void
2864 atom_moov_add_tag (AtomMOOV * moov, guint32 fourcc, guint32 flags,
2865     const guint8 * data, guint size)
2866 {
2867   AtomTag *tag;
2868   AtomTagData *tdata;
2869
2870   tag = atom_tag_new (fourcc, flags);
2871   tdata = &tag->data;
2872   atom_tag_data_alloc_data (tdata, size);
2873   g_memmove (tdata->data, data, size);
2874
2875   atom_moov_append_tag (moov,
2876       build_atom_info_wrapper ((Atom *) tag, atom_tag_copy_data,
2877           atom_tag_free));
2878 }
2879
2880 void
2881 atom_moov_add_str_tag (AtomMOOV * moov, guint32 fourcc, const gchar * value)
2882 {
2883   gint len = strlen (value);
2884
2885   if (len > 0)
2886     atom_moov_add_tag (moov, fourcc, METADATA_TEXT_FLAG, (guint8 *) value, len);
2887 }
2888
2889 void
2890 atom_moov_add_uint_tag (AtomMOOV * moov, guint32 fourcc, guint32 flags,
2891     guint32 value)
2892 {
2893   guint8 data[8] = { 0, };
2894
2895   if (flags) {
2896     GST_WRITE_UINT16_BE (data, value);
2897     atom_moov_add_tag (moov, fourcc, flags, data, 2);
2898   } else {
2899     GST_WRITE_UINT32_BE (data + 2, value);
2900     atom_moov_add_tag (moov, fourcc, flags, data, 8);
2901   }
2902 }
2903
2904 static GstBuffer *
2905 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
2906 {
2907   GstBuffer *buf;
2908
2909   buf = gst_buffer_new ();
2910   gst_buffer_take_memory (buf, -1,
2911       gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
2912           mem, free_func, size, 0, size));
2913
2914   return buf;
2915 }
2916
2917 void
2918 atom_moov_add_blob_tag (AtomMOOV * moov, guint8 * data, guint size)
2919 {
2920   AtomData *data_atom;
2921   GstBuffer *buf;
2922   guint len;
2923   guint32 fourcc;
2924
2925   if (size < 8)
2926     return;
2927
2928   /* blob is unparsed atom;
2929    * extract size and fourcc, and wrap remainder in data atom */
2930   len = GST_READ_UINT32_BE (data);
2931   fourcc = GST_READ_UINT32_LE (data + 4);
2932   if (len > size)
2933     return;
2934
2935   buf = _gst_buffer_new_wrapped (data + 8, len - 8, NULL);
2936   data_atom = atom_data_new_from_gst_buffer (fourcc, buf);
2937   gst_buffer_unref (buf);
2938
2939   atom_moov_append_tag (moov,
2940       build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
2941           atom_data_free));
2942 }
2943
2944 void
2945 atom_moov_add_3gp_tag (AtomMOOV * moov, guint32 fourcc, guint8 * data,
2946     guint size)
2947 {
2948   AtomData *data_atom;
2949   GstBuffer *buf;
2950   guint8 *bdata;
2951
2952   /* need full atom */
2953   bdata = g_malloc (size + 4);
2954   /* full atom: version and flags */
2955   GST_WRITE_UINT32_BE (bdata, 0);
2956   memcpy (bdata + 4, data, size);
2957
2958   buf = _gst_buffer_new_wrapped (bdata, size + 4, g_free);
2959   data_atom = atom_data_new_from_gst_buffer (fourcc, buf);
2960   gst_buffer_unref (buf);
2961
2962   atom_moov_append_tag (moov,
2963       build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
2964           atom_data_free));
2965 }
2966
2967 guint16
2968 language_code (const char *lang)
2969 {
2970   g_return_val_if_fail (lang != NULL, 0);
2971   g_return_val_if_fail (strlen (lang) == 3, 0);
2972
2973   return (((lang[0] - 0x60) & 0x1F) << 10) + (((lang[1] - 0x60) & 0x1F) << 5) +
2974       ((lang[2] - 0x60) & 0x1F);
2975 }
2976
2977 void
2978 atom_moov_add_3gp_str_int_tag (AtomMOOV * moov, guint32 fourcc,
2979     const gchar * value, gint16 ivalue)
2980 {
2981   gint len = 0, size = 0;
2982   guint8 *data;
2983
2984   if (value) {
2985     len = strlen (value);
2986     size = len + 3;
2987   }
2988
2989   if (ivalue >= 0)
2990     size += 2;
2991
2992   data = g_malloc (size + 3);
2993   /* language tag and null-terminated UTF-8 string */
2994   if (value) {
2995     GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
2996     /* include 0 terminator */
2997     memcpy (data + 2, value, len + 1);
2998   }
2999   /* 16-bit unsigned int if standalone, otherwise 8-bit */
3000   if (ivalue >= 0) {
3001     if (size == 2)
3002       GST_WRITE_UINT16_BE (data + size - 2, ivalue);
3003     else {
3004       GST_WRITE_UINT8 (data + size - 2, ivalue & 0xFF);
3005       size--;
3006     }
3007   }
3008
3009   atom_moov_add_3gp_tag (moov, fourcc, data, size);
3010   g_free (data);
3011 }
3012
3013 void
3014 atom_moov_add_3gp_str_tag (AtomMOOV * moov, guint32 fourcc, const gchar * value)
3015 {
3016   atom_moov_add_3gp_str_int_tag (moov, fourcc, value, -1);
3017 }
3018
3019 void
3020 atom_moov_add_3gp_uint_tag (AtomMOOV * moov, guint32 fourcc, guint16 value)
3021 {
3022   atom_moov_add_3gp_str_int_tag (moov, fourcc, NULL, value);
3023 }
3024
3025 void
3026 atom_moov_add_xmp_tags (AtomMOOV * moov, GstBuffer * xmpbuffer)
3027 {
3028   AtomData *data_atom = NULL;
3029
3030   if (moov->context.flavor == ATOMS_TREE_FLAVOR_MOV) {
3031     if (xmpbuffer) {
3032       data_atom = atom_data_new_from_gst_buffer (FOURCC_XMP_, xmpbuffer);
3033       atom_moov_init_metatags (moov, &moov->context);
3034       moov->udta->entries = g_list_append (moov->udta->entries,
3035           build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
3036               atom_data_free));
3037     }
3038   } else {
3039     GST_DEBUG ("Not adding xmp to moov atom, it is only used in 'mov' format");
3040   }
3041
3042 }
3043
3044 /*
3045  * Functions for specifying media types
3046  */
3047
3048 static void
3049 atom_minf_set_audio (AtomMINF * minf)
3050 {
3051   atom_minf_clear_handlers (minf);
3052   minf->smhd = atom_smhd_new ();
3053 }
3054
3055 static void
3056 atom_minf_set_video (AtomMINF * minf, AtomsContext * context)
3057 {
3058   atom_minf_clear_handlers (minf);
3059   minf->vmhd = atom_vmhd_new (context);
3060 }
3061
3062 static void
3063 atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type,
3064     guint32 hdlr_type)
3065 {
3066   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
3067     hdlr->component_type = comp_type;
3068   }
3069   hdlr->handler_type = hdlr_type;
3070 }
3071
3072 static void
3073 atom_hdlr_set_name (AtomHDLR * hdlr, const char *name)
3074 {
3075   if (hdlr->name)
3076     g_free (hdlr->name);
3077   hdlr->name = g_strdup (name);
3078 }
3079
3080 static void
3081 atom_mdia_set_hdlr_type_audio (AtomMDIA * mdia, AtomsContext * context)
3082 {
3083   atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_soun);
3084   /* Some players (low-end hardware) check for this name, which is what
3085    * QuickTime itself sets */
3086   atom_hdlr_set_name (&mdia->hdlr, "SoundHandler");
3087 }
3088
3089 static void
3090 atom_mdia_set_hdlr_type_video (AtomMDIA * mdia, AtomsContext * context)
3091 {
3092   atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_vide);
3093   /* Some players (low-end hardware) check for this name, which is what
3094    * QuickTime itself sets */
3095   atom_hdlr_set_name (&mdia->hdlr, "VideoHandler");
3096 }
3097
3098 static void
3099 atom_mdia_set_audio (AtomMDIA * mdia, AtomsContext * context)
3100 {
3101   atom_mdia_set_hdlr_type_audio (mdia, context);
3102   atom_minf_set_audio (&mdia->minf);
3103 }
3104
3105 static void
3106 atom_mdia_set_video (AtomMDIA * mdia, AtomsContext * context)
3107 {
3108   atom_mdia_set_hdlr_type_video (mdia, context);
3109   atom_minf_set_video (&mdia->minf, context);
3110 }
3111
3112 static void
3113 atom_tkhd_set_audio (AtomTKHD * tkhd)
3114 {
3115   tkhd->volume = 0x0100;
3116   tkhd->width = tkhd->height = 0;
3117 }
3118
3119 static void
3120 atom_tkhd_set_video (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
3121     guint32 height)
3122 {
3123   tkhd->volume = 0;
3124
3125   /* qt and ISO base media do not contradict, and examples agree */
3126   tkhd->width = width;
3127   tkhd->height = height;
3128 }
3129
3130 static void
3131 atom_edts_add_entry (AtomEDTS * edts, EditListEntry * entry)
3132 {
3133   edts->elst.entries = g_slist_append (edts->elst.entries, entry);
3134 }
3135
3136 /* 
3137  * Adds a new entry to this trak edits list
3138  * duration is in the moov's timescale
3139  * media_time is the offset in the media time to start from (media's timescale)
3140  * rate is a 32 bits fixed-point
3141  */
3142 void
3143 atom_trak_add_elst_entry (AtomTRAK * trak, guint32 duration, guint32 media_time,
3144     guint32 rate)
3145 {
3146   EditListEntry *entry = g_new (EditListEntry, 1);
3147
3148   entry->duration = duration;
3149   entry->media_time = media_time;
3150   entry->media_rate = rate;
3151
3152   if (trak->edts == NULL) {
3153     trak->edts = atom_edts_new ();
3154   }
3155   atom_edts_add_entry (trak->edts, entry);
3156 }
3157
3158 /* re-negotiation is prevented at top-level, so only 1 entry expected.
3159  * Quite some more care here and elsewhere may be needed to
3160  * support several entries */
3161 static SampleTableEntryMP4A *
3162 atom_trak_add_audio_entry (AtomTRAK * trak, AtomsContext * context,
3163     guint32 type)
3164 {
3165   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
3166   SampleTableEntryMP4A *mp4a = sample_entry_mp4a_new ();
3167
3168   mp4a->se.header.type = type;
3169   mp4a->se.kind = AUDIO;
3170   mp4a->compression_id = -1;
3171   mp4a->se.data_reference_index = 1;
3172
3173   stsd->entries = g_list_prepend (stsd->entries, mp4a);
3174   stsd->n_entries++;
3175   return mp4a;
3176 }
3177
3178 static SampleTableEntryMP4V *
3179 atom_trak_add_video_entry (AtomTRAK * trak, AtomsContext * context,
3180     guint32 type)
3181 {
3182   SampleTableEntryMP4V *mp4v = sample_entry_mp4v_new (context);
3183   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
3184
3185   mp4v->se.header.type = type;
3186   mp4v->se.kind = VIDEO;
3187   mp4v->se.data_reference_index = 1;
3188   mp4v->horizontal_resolution = 72 << 16;
3189   mp4v->vertical_resolution = 72 << 16;
3190   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
3191     mp4v->spatial_quality = 512;
3192     mp4v->temporal_quality = 512;
3193   }
3194
3195   stsd->entries = g_list_prepend (stsd->entries, mp4v);
3196   stsd->n_entries++;
3197   return mp4v;
3198 }
3199
3200 static void
3201 atom_trak_set_constant_size_samples (AtomTRAK * trak, guint32 sample_size)
3202 {
3203   trak->mdia.minf.stbl.stsz.sample_size = sample_size;
3204 }
3205
3206 static void
3207 atom_trak_set_audio (AtomTRAK * trak, AtomsContext * context)
3208 {
3209   atom_tkhd_set_audio (&trak->tkhd);
3210   atom_mdia_set_audio (&trak->mdia, context);
3211 }
3212
3213 static void
3214 atom_trak_set_video (AtomTRAK * trak, AtomsContext * context, guint32 width,
3215     guint32 height)
3216 {
3217   atom_tkhd_set_video (&trak->tkhd, context, width, height);
3218   atom_mdia_set_video (&trak->mdia, context);
3219 }
3220
3221 static void
3222 atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context,
3223     guint32 rate)
3224 {
3225   atom_trak_set_audio (trak, context);
3226   trak->mdia.mdhd.time_info.timescale = rate;
3227 }
3228
3229 static void
3230 atom_trak_set_video_commons (AtomTRAK * trak, AtomsContext * context,
3231     guint32 rate, guint32 width, guint32 height)
3232 {
3233   atom_trak_set_video (trak, context, width, height);
3234   trak->mdia.mdhd.time_info.timescale = rate;
3235   trak->tkhd.width = width << 16;
3236   trak->tkhd.height = height << 16;
3237 }
3238
3239 void
3240 atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
3241     AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size)
3242 {
3243   SampleTableEntryMP4A *ste;
3244
3245   atom_trak_set_audio_commons (trak, context, scale);
3246   atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
3247   ste = atom_trak_add_audio_entry (trak, context, entry->fourcc);
3248
3249   trak->is_video = FALSE;
3250   trak->is_h264 = FALSE;
3251
3252   ste->version = entry->version;
3253   ste->compression_id = entry->compression_id;
3254   ste->sample_size = entry->sample_size;
3255   ste->sample_rate = entry->sample_rate << 16;
3256   ste->channels = entry->channels;
3257
3258   ste->samples_per_packet = entry->samples_per_packet;
3259   ste->bytes_per_sample = entry->bytes_per_sample;
3260   ste->bytes_per_packet = entry->bytes_per_packet;
3261   ste->bytes_per_frame = entry->bytes_per_frame;
3262
3263   if (ext)
3264     ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext);
3265
3266   /* 0 size means variable size */
3267   atom_trak_set_constant_size_samples (trak, sample_size);
3268 }
3269
3270 static AtomInfo *
3271 build_pasp_extension (AtomTRAK * trak, gint par_width, gint par_height)
3272 {
3273   AtomData *atom_data;
3274   GstBuffer *buf;
3275   guint8 *data;
3276
3277   data = g_malloc (8);
3278   /* ihdr = image header box */
3279   GST_WRITE_UINT32_BE (data, par_width);
3280   GST_WRITE_UINT32_BE (data + 4, par_height);
3281
3282   buf = _gst_buffer_new_wrapped (data, 8, g_free);
3283   atom_data = atom_data_new_from_gst_buffer (FOURCC_pasp, buf);
3284   gst_buffer_unref (buf);
3285
3286   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
3287       atom_data_free);
3288 }
3289
3290 void
3291 atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
3292     VisualSampleEntry * entry, guint32 scale, GList * ext_atoms_list)
3293 {
3294   SampleTableEntryMP4V *ste;
3295   gint dwidth, dheight;
3296   gint par_n = 0, par_d = 0;
3297
3298   if ((entry->par_n != 1 || entry->par_d != 1) &&
3299       (entry->par_n != entry->par_d)) {
3300     par_n = entry->par_n;
3301     par_d = entry->par_d;
3302   }
3303
3304   dwidth = entry->width;
3305   dheight = entry->height;
3306   /* ISO file spec says track header w/h indicates track's visual presentation
3307    * (so this together with pixels w/h implicitly defines PAR) */
3308   if (par_n && (context->flavor != ATOMS_TREE_FLAVOR_MOV)) {
3309     if (par_n > par_d) {
3310       dwidth = entry->width * par_n / par_d;
3311       dheight = entry->height;
3312     } else {
3313       dwidth = entry->width * par_n / par_d;
3314       dheight = entry->height;
3315     }
3316   }
3317
3318   atom_trak_set_video_commons (trak, context, scale, dwidth, dheight);
3319   atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
3320   ste = atom_trak_add_video_entry (trak, context, entry->fourcc);
3321
3322   trak->is_video = TRUE;
3323   trak->is_h264 = (entry->fourcc == FOURCC_avc1);
3324
3325   ste->version = entry->version;
3326   ste->width = entry->width;
3327   ste->height = entry->height;
3328   ste->depth = entry->depth;
3329   ste->color_table_id = entry->color_table_id;
3330   ste->frame_count = entry->frame_count;
3331
3332   if (ext_atoms_list)
3333     ste->extension_atoms = g_list_concat (ste->extension_atoms, ext_atoms_list);
3334
3335   /* QT spec has a pasp extension atom in stsd that can hold PAR */
3336   if (par_n && (context->flavor == ATOMS_TREE_FLAVOR_MOV)) {
3337     ste->extension_atoms = g_list_append (ste->extension_atoms,
3338         build_pasp_extension (trak, par_n, par_d));
3339   }
3340 }
3341
3342 static void
3343 atom_mfhd_init (AtomMFHD * mfhd, guint32 sequence_number)
3344 {
3345   guint8 flags[3] = { 0, 0, 0 };
3346
3347   atom_full_init (&(mfhd->header), FOURCC_mfhd, 0, 0, 0, flags);
3348   mfhd->sequence_number = sequence_number;
3349 }
3350
3351 static void
3352 atom_moof_init (AtomMOOF * moof, AtomsContext * context,
3353     guint32 sequence_number)
3354 {
3355   atom_header_set (&moof->header, FOURCC_moof, 0, 0);
3356   atom_mfhd_init (&moof->mfhd, sequence_number);
3357   moof->trafs = NULL;
3358 }
3359
3360 AtomMOOF *
3361 atom_moof_new (AtomsContext * context, guint32 sequence_number)
3362 {
3363   AtomMOOF *moof = g_new0 (AtomMOOF, 1);
3364
3365   atom_moof_init (moof, context, sequence_number);
3366   return moof;
3367 }
3368
3369 static void
3370 atom_trun_free (AtomTRUN * trun)
3371 {
3372   atom_full_clear (&trun->header);
3373   atom_array_clear (&trun->entries);
3374   g_free (trun);
3375 }
3376
3377 static void
3378 atom_sdtp_free (AtomSDTP * sdtp)
3379 {
3380   atom_full_clear (&sdtp->header);
3381   atom_array_clear (&sdtp->entries);
3382   g_free (sdtp);
3383 }
3384
3385 void
3386 atom_traf_free (AtomTRAF * traf)
3387 {
3388   GList *walker;
3389
3390   walker = traf->truns;
3391   while (walker) {
3392     atom_trun_free ((AtomTRUN *) walker->data);
3393     walker = g_list_next (walker);
3394   }
3395   g_list_free (traf->truns);
3396   traf->truns = NULL;
3397
3398   walker = traf->sdtps;
3399   while (walker) {
3400     atom_sdtp_free ((AtomSDTP *) walker->data);
3401     walker = g_list_next (walker);
3402   }
3403   g_list_free (traf->sdtps);
3404   traf->sdtps = NULL;
3405
3406   g_free (traf);
3407 }
3408
3409 void
3410 atom_moof_free (AtomMOOF * moof)
3411 {
3412   GList *walker;
3413
3414   walker = moof->trafs;
3415   while (walker) {
3416     atom_traf_free ((AtomTRAF *) walker->data);
3417     walker = g_list_next (walker);
3418   }
3419   g_list_free (moof->trafs);
3420   moof->trafs = NULL;
3421
3422   g_free (moof);
3423 }
3424
3425 static guint64
3426 atom_mfhd_copy_data (AtomMFHD * mfhd, guint8 ** buffer, guint64 * size,
3427     guint64 * offset)
3428 {
3429   guint64 original_offset = *offset;
3430
3431   if (!atom_full_copy_data (&mfhd->header, buffer, size, offset)) {
3432     return 0;
3433   }
3434
3435   prop_copy_uint32 (mfhd->sequence_number, buffer, size, offset);
3436
3437   atom_write_size (buffer, size, offset, original_offset);
3438   return *offset - original_offset;
3439 }
3440
3441 static guint64
3442 atom_tfhd_copy_data (AtomTFHD * tfhd, guint8 ** buffer, guint64 * size,
3443     guint64 * offset)
3444 {
3445   guint64 original_offset = *offset;
3446   guint32 flags;
3447
3448   if (!atom_full_copy_data (&tfhd->header, buffer, size, offset)) {
3449     return 0;
3450   }
3451
3452   prop_copy_uint32 (tfhd->track_ID, buffer, size, offset);
3453
3454   flags = atom_full_get_flags_as_uint (&tfhd->header);
3455
3456   if (flags & TF_BASE_DATA_OFFSET)
3457     prop_copy_uint64 (tfhd->base_data_offset, buffer, size, offset);
3458   if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3459     prop_copy_uint32 (tfhd->sample_description_index, buffer, size, offset);
3460   if (flags & TF_DEFAULT_SAMPLE_DURATION)
3461     prop_copy_uint32 (tfhd->default_sample_duration, buffer, size, offset);
3462   if (flags & TF_DEFAULT_SAMPLE_SIZE)
3463     prop_copy_uint32 (tfhd->default_sample_size, buffer, size, offset);
3464   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3465     prop_copy_uint32 (tfhd->default_sample_flags, buffer, size, offset);
3466
3467   atom_write_size (buffer, size, offset, original_offset);
3468   return *offset - original_offset;
3469 }
3470
3471 static guint64
3472 atom_trun_copy_data (AtomTRUN * trun, guint8 ** buffer, guint64 * size,
3473     guint64 * offset, guint32 * data_offset)
3474 {
3475   guint64 original_offset = *offset;
3476   guint32 flags, i;
3477
3478   flags = atom_full_get_flags_as_uint (&trun->header);
3479
3480   /* if first trun in moof, forcibly add data_offset and record
3481    * where it must be written later on */
3482   if (data_offset && !*data_offset) {
3483     flags |= TR_DATA_OFFSET;
3484   } else {
3485     flags &= ~TR_DATA_OFFSET;
3486   }
3487
3488   atom_full_set_flags_as_uint (&trun->header, flags);
3489
3490   if (!atom_full_copy_data (&trun->header, buffer, size, offset)) {
3491     return 0;
3492   }
3493
3494   prop_copy_uint32 (trun->sample_count, buffer, size, offset);
3495
3496   if (flags & TR_DATA_OFFSET) {
3497     *data_offset = *offset;
3498     prop_copy_int32 (trun->data_offset, buffer, size, offset);
3499   }
3500   if (flags & TR_FIRST_SAMPLE_FLAGS)
3501     prop_copy_uint32 (trun->first_sample_flags, buffer, size, offset);
3502
3503   for (i = 0; i < atom_array_get_len (&trun->entries); i++) {
3504     TRUNSampleEntry *entry = &atom_array_index (&trun->entries, i);
3505
3506     if (flags & TR_SAMPLE_DURATION)
3507       prop_copy_uint32 (entry->sample_duration, buffer, size, offset);
3508     if (flags & TR_SAMPLE_SIZE)
3509       prop_copy_uint32 (entry->sample_size, buffer, size, offset);
3510     if (flags & TR_SAMPLE_FLAGS)
3511       prop_copy_uint32 (entry->sample_flags, buffer, size, offset);
3512     if (flags & TR_COMPOSITION_TIME_OFFSETS)
3513       prop_copy_uint32 (entry->sample_composition_time_offset,
3514           buffer, size, offset);
3515   }
3516
3517   atom_write_size (buffer, size, offset, original_offset);
3518   return *offset - original_offset;
3519 }
3520
3521 static guint64
3522 atom_sdtp_copy_data (AtomSDTP * sdtp, guint8 ** buffer, guint64 * size,
3523     guint64 * offset)
3524 {
3525   guint64 original_offset = *offset;
3526
3527   if (!atom_full_copy_data (&sdtp->header, buffer, size, offset)) {
3528     return 0;
3529   }
3530
3531   /* all entries at once */
3532   prop_copy_fixed_size_string (&atom_array_index (&sdtp->entries, 0),
3533       atom_array_get_len (&sdtp->entries), buffer, size, offset);
3534
3535   atom_write_size (buffer, size, offset, original_offset);
3536   return *offset - original_offset;
3537 }
3538
3539 static guint64
3540 atom_traf_copy_data (AtomTRAF * traf, guint8 ** buffer, guint64 * size,
3541     guint64 * offset, guint32 * data_offset)
3542 {
3543   guint64 original_offset = *offset;
3544   GList *walker;
3545
3546   if (!atom_copy_data (&traf->header, buffer, size, offset)) {
3547     return 0;
3548   }
3549   if (!atom_tfhd_copy_data (&traf->tfhd, buffer, size, offset)) {
3550     return 0;
3551   }
3552
3553   walker = g_list_first (traf->truns);
3554   while (walker != NULL) {
3555     if (!atom_trun_copy_data ((AtomTRUN *) walker->data, buffer, size, offset,
3556             data_offset)) {
3557       return 0;
3558     }
3559     walker = g_list_next (walker);
3560   }
3561
3562   walker = g_list_first (traf->sdtps);
3563   while (walker != NULL) {
3564     if (!atom_sdtp_copy_data ((AtomSDTP *) walker->data, buffer, size, offset)) {
3565       return 0;
3566     }
3567     walker = g_list_next (walker);
3568   }
3569
3570   atom_write_size (buffer, size, offset, original_offset);
3571   return *offset - original_offset;
3572 }
3573
3574 /* creates moof atom; metadata is written expecting actual buffer data
3575  * is in mdata directly after moof, and is consecutively written per trak */
3576 guint64
3577 atom_moof_copy_data (AtomMOOF * moof, guint8 ** buffer,
3578     guint64 * size, guint64 * offset)
3579 {
3580   guint64 original_offset = *offset;
3581   GList *walker;
3582   guint32 data_offset = 0;
3583
3584   if (!atom_copy_data (&moof->header, buffer, size, offset))
3585     return 0;
3586
3587   if (!atom_mfhd_copy_data (&moof->mfhd, buffer, size, offset))
3588     return 0;
3589
3590   walker = g_list_first (moof->trafs);
3591   while (walker != NULL) {
3592     if (!atom_traf_copy_data ((AtomTRAF *) walker->data, buffer, size, offset,
3593             &data_offset)) {
3594       return 0;
3595     }
3596     walker = g_list_next (walker);
3597   }
3598
3599   atom_write_size (buffer, size, offset, original_offset);
3600
3601   if (*buffer && data_offset) {
3602     /* first trun needs a data-offset relative to moof start
3603      *   = moof size + mdat prefix */
3604     GST_WRITE_UINT32_BE (*buffer + data_offset, *offset - original_offset + 8);
3605   }
3606
3607   return *offset - original_offset;
3608 }
3609
3610 static void
3611 atom_tfhd_init (AtomTFHD * tfhd, guint32 track_ID)
3612 {
3613   guint8 flags[3] = { 0, 0, 0 };
3614
3615   atom_full_init (&tfhd->header, FOURCC_tfhd, 0, 0, 0, flags);
3616   tfhd->track_ID = track_ID;
3617   tfhd->base_data_offset = 0;
3618   tfhd->sample_description_index = 1;
3619   tfhd->default_sample_duration = 0;
3620   tfhd->default_sample_size = 0;
3621   tfhd->default_sample_flags = 0;
3622 }
3623
3624 static void
3625 atom_trun_init (AtomTRUN * trun)
3626 {
3627   guint8 flags[3] = { 0, 0, 0 };
3628
3629   atom_full_init (&trun->header, FOURCC_trun, 0, 0, 0, flags);
3630   trun->sample_count = 0;
3631   trun->data_offset = 0;
3632   trun->first_sample_flags = 0;
3633   atom_array_init (&trun->entries, 512);
3634 }
3635
3636 static AtomTRUN *
3637 atom_trun_new (void)
3638 {
3639   AtomTRUN *trun = g_new0 (AtomTRUN, 1);
3640
3641   atom_trun_init (trun);
3642   return trun;
3643 }
3644
3645 static void
3646 atom_sdtp_init (AtomSDTP * sdtp)
3647 {
3648   guint8 flags[3] = { 0, 0, 0 };
3649
3650   atom_full_init (&sdtp->header, FOURCC_sdtp, 0, 0, 0, flags);
3651   atom_array_init (&sdtp->entries, 512);
3652 }
3653
3654 static AtomSDTP *
3655 atom_sdtp_new (AtomsContext * context)
3656 {
3657   AtomSDTP *sdtp = g_new0 (AtomSDTP, 1);
3658
3659   atom_sdtp_init (sdtp);
3660   return sdtp;
3661 }
3662
3663 static void
3664 atom_traf_add_sdtp (AtomTRAF * traf, AtomSDTP * sdtp)
3665 {
3666   traf->sdtps = g_list_append (traf->sdtps, sdtp);
3667 }
3668
3669 static void
3670 atom_sdtp_add_samples (AtomSDTP * sdtp, guint8 val)
3671 {
3672   /* it does not make much/any sense according to specs,
3673    * but that's how MS isml samples seem to do it */
3674   atom_array_append (&sdtp->entries, val, 256);
3675 }
3676
3677 static void
3678 atom_trun_add_samples (AtomTRUN * trun, guint32 delta, guint32 size,
3679     guint32 flags, gint64 pts_offset)
3680 {
3681   TRUNSampleEntry nentry;
3682
3683   if (pts_offset != 0)
3684     trun->header.flags[1] |= TR_COMPOSITION_TIME_OFFSETS;
3685
3686   nentry.sample_duration = delta;
3687   nentry.sample_size = size;
3688   nentry.sample_flags = flags;
3689   nentry.sample_composition_time_offset = pts_offset;
3690   atom_array_append (&trun->entries, nentry, 256);
3691   trun->sample_count++;
3692 }
3693
3694 static void
3695 atom_traf_init (AtomTRAF * traf, AtomsContext * context, guint32 track_ID)
3696 {
3697   atom_header_set (&traf->header, FOURCC_traf, 0, 0);
3698   atom_tfhd_init (&traf->tfhd, track_ID);
3699   traf->truns = NULL;
3700
3701   if (context->flavor == ATOMS_TREE_FLAVOR_ISML)
3702     atom_traf_add_sdtp (traf, atom_sdtp_new (context));
3703 }
3704
3705 AtomTRAF *
3706 atom_traf_new (AtomsContext * context, guint32 track_ID)
3707 {
3708   AtomTRAF *traf = g_new0 (AtomTRAF, 1);
3709
3710   atom_traf_init (traf, context, track_ID);
3711   return traf;
3712 }
3713
3714 static void
3715 atom_traf_add_trun (AtomTRAF * traf, AtomTRUN * trun)
3716 {
3717   traf->truns = g_list_append (traf->truns, trun);
3718 }
3719
3720 void
3721 atom_traf_add_samples (AtomTRAF * traf, guint32 delta, guint32 size,
3722     gboolean sync, gint64 pts_offset, gboolean sdtp_sync)
3723 {
3724   AtomTRUN *trun;
3725   guint32 flags;
3726
3727   /* 0x10000 is sample-is-difference-sample flag
3728    * low byte stuff is what ismv uses */
3729   flags = (sync ? 0x0 : 0x10000) | (sdtp_sync ? 0x40 : 0xc0);
3730
3731   if (G_UNLIKELY (!traf->truns)) {
3732     trun = atom_trun_new ();
3733     atom_traf_add_trun (traf, trun);
3734     /* optimistic; indicate all defaults present in tfhd */
3735     traf->tfhd.header.flags[2] = TF_DEFAULT_SAMPLE_DURATION |
3736         TF_DEFAULT_SAMPLE_SIZE | TF_DEFAULT_SAMPLE_FLAGS;
3737     traf->tfhd.default_sample_duration = delta;
3738     traf->tfhd.default_sample_size = size;
3739     traf->tfhd.default_sample_flags = flags;
3740     trun->first_sample_flags = flags;
3741   }
3742
3743   trun = traf->truns->data;
3744
3745   /* check if still matching defaults,
3746    * if not, abandon default and need entry for each sample */
3747   if (traf->tfhd.default_sample_duration != delta) {
3748     traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_DURATION;
3749     trun->header.flags[1] |= (TR_SAMPLE_DURATION >> 8);
3750   }
3751   if (traf->tfhd.default_sample_size != size) {
3752     traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_SIZE;
3753     trun->header.flags[1] |= (TR_SAMPLE_SIZE >> 8);
3754   }
3755   if (traf->tfhd.default_sample_flags != flags) {
3756     if (trun->sample_count == 1) {
3757       /* at least will need first sample flag */
3758       traf->tfhd.default_sample_flags = flags;
3759       trun->header.flags[2] |= TR_FIRST_SAMPLE_FLAGS;
3760     } else {
3761       /* now we need sample flags for each sample */
3762       traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_FLAGS;
3763       trun->header.flags[1] |= (TR_SAMPLE_FLAGS >> 8);
3764       trun->header.flags[2] &= ~TR_FIRST_SAMPLE_FLAGS;
3765     }
3766   }
3767
3768   atom_trun_add_samples (traf->truns->data, delta, size, flags, pts_offset);
3769
3770   if (traf->sdtps)
3771     atom_sdtp_add_samples (traf->sdtps->data, 0x10 | ((flags & 0xff) >> 4));
3772 }
3773
3774 guint32
3775 atom_traf_get_sample_num (AtomTRAF * traf)
3776 {
3777   AtomTRUN *trun;
3778
3779   if (G_UNLIKELY (!traf->truns))
3780     return 0;
3781
3782   trun = traf->truns->data;
3783   return atom_array_get_len (&trun->entries);
3784 }
3785
3786 void
3787 atom_moof_add_traf (AtomMOOF * moof, AtomTRAF * traf)
3788 {
3789   moof->trafs = g_list_append (moof->trafs, traf);
3790 }
3791
3792 static void
3793 atom_tfra_free (AtomTFRA * tfra)
3794 {
3795   atom_full_clear (&tfra->header);
3796   atom_array_clear (&tfra->entries);
3797   g_free (tfra);
3798 }
3799
3800 AtomMFRA *
3801 atom_mfra_new (AtomsContext * context)
3802 {
3803   AtomMFRA *mfra = g_new0 (AtomMFRA, 1);
3804
3805   atom_header_set (&mfra->header, FOURCC_mfra, 0, 0);
3806   return mfra;
3807 }
3808
3809 void
3810 atom_mfra_add_tfra (AtomMFRA * mfra, AtomTFRA * tfra)
3811 {
3812   mfra->tfras = g_list_append (mfra->tfras, tfra);
3813 }
3814
3815 void
3816 atom_mfra_free (AtomMFRA * mfra)
3817 {
3818   GList *walker;
3819
3820   walker = mfra->tfras;
3821   while (walker) {
3822     atom_tfra_free ((AtomTFRA *) walker->data);
3823     walker = g_list_next (walker);
3824   }
3825   g_list_free (mfra->tfras);
3826   mfra->tfras = NULL;
3827
3828   atom_clear (&mfra->header);
3829   g_free (mfra);
3830 }
3831
3832 static void
3833 atom_tfra_init (AtomTFRA * tfra, guint32 track_ID)
3834 {
3835   guint8 flags[3] = { 0, 0, 0 };
3836
3837   atom_full_init (&tfra->header, FOURCC_tfra, 0, 0, 0, flags);
3838   tfra->track_ID = track_ID;
3839   atom_array_init (&tfra->entries, 512);
3840 }
3841
3842 AtomTFRA *
3843 atom_tfra_new (AtomsContext * context, guint32 track_ID)
3844 {
3845   AtomTFRA *tfra = g_new0 (AtomTFRA, 1);
3846
3847   atom_tfra_init (tfra, track_ID);
3848   return tfra;
3849
3850 }
3851
3852 static inline gint
3853 need_bytes (guint32 num)
3854 {
3855   gint n = 0;
3856
3857   while (num >>= 8)
3858     n++;
3859
3860   return n;
3861 }
3862
3863 void
3864 atom_tfra_add_entry (AtomTFRA * tfra, guint64 dts, guint32 sample_num)
3865 {
3866   TFRAEntry entry;
3867
3868   entry.time = dts;
3869   /* fill in later */
3870   entry.moof_offset = 0;
3871   /* always write a single trun in a single traf */
3872   entry.traf_number = 1;
3873   entry.trun_number = 1;
3874   entry.sample_number = sample_num;
3875
3876   /* auto-use 64 bits if needed */
3877   if (dts > G_MAXUINT32)
3878     tfra->header.version = 1;
3879
3880   /* 1 byte will always do for traf and trun number,
3881    * check how much sample_num needs */
3882   tfra->lengths = (tfra->lengths & 0xfc) ||
3883       MAX (tfra->lengths, need_bytes (sample_num));
3884
3885   atom_array_append (&tfra->entries, entry, 256);
3886 }
3887
3888 void
3889 atom_tfra_update_offset (AtomTFRA * tfra, guint64 offset)
3890 {
3891   gint i;
3892
3893   /* auto-use 64 bits if needed */
3894   if (offset > G_MAXUINT32)
3895     tfra->header.version = 1;
3896
3897   for (i = atom_array_get_len (&tfra->entries) - 1; i >= 0; i--) {
3898     TFRAEntry *entry = &atom_array_index (&tfra->entries, i);
3899
3900     if (entry->moof_offset)
3901       break;
3902     entry->moof_offset = offset;
3903   }
3904 }
3905
3906 static guint64
3907 atom_tfra_copy_data (AtomTFRA * tfra, guint8 ** buffer, guint64 * size,
3908     guint64 * offset)
3909 {
3910   guint64 original_offset = *offset;
3911   guint32 i;
3912   TFRAEntry *entry;
3913   guint32 data;
3914   guint bytes;
3915   guint version;
3916
3917   if (!atom_full_copy_data (&tfra->header, buffer, size, offset)) {
3918     return 0;
3919   }
3920
3921   prop_copy_uint32 (tfra->track_ID, buffer, size, offset);
3922   prop_copy_uint32 (tfra->lengths, buffer, size, offset);
3923   prop_copy_uint32 (atom_array_get_len (&tfra->entries), buffer, size, offset);
3924
3925   version = tfra->header.version;
3926   for (i = 0; i < atom_array_get_len (&tfra->entries); ++i) {
3927     entry = &atom_array_index (&tfra->entries, i);
3928     if (version) {
3929       prop_copy_uint64 (entry->time, buffer, size, offset);
3930       prop_copy_uint64 (entry->moof_offset, buffer, size, offset);
3931     } else {
3932       prop_copy_uint32 (entry->time, buffer, size, offset);
3933       prop_copy_uint32 (entry->moof_offset, buffer, size, offset);
3934     }
3935
3936     bytes = (tfra->lengths & (0x3 << 4)) + 1;
3937     data = GUINT32_TO_BE (entry->traf_number);
3938     prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
3939         buffer, size, offset);
3940
3941     bytes = (tfra->lengths & (0x3 << 2)) + 1;
3942     data = GUINT32_TO_BE (entry->trun_number);
3943     prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
3944         buffer, size, offset);
3945
3946     bytes = (tfra->lengths & (0x3)) + 1;
3947     data = GUINT32_TO_BE (entry->sample_number);
3948     prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
3949         buffer, size, offset);
3950
3951   }
3952
3953   atom_write_size (buffer, size, offset, original_offset);
3954   return *offset - original_offset;
3955 }
3956
3957 static guint64
3958 atom_mfro_copy_data (guint32 s, guint8 ** buffer, guint64 * size,
3959     guint64 * offset)
3960 {
3961   guint64 original_offset = *offset;
3962   guint8 flags[3] = { 0, 0, 0 };
3963   AtomFull mfro;
3964
3965   atom_full_init (&mfro, FOURCC_mfro, 0, 0, 0, flags);
3966
3967   if (!atom_full_copy_data (&mfro, buffer, size, offset)) {
3968     return 0;
3969   }
3970
3971   prop_copy_uint32 (s, buffer, size, offset);
3972
3973   atom_write_size (buffer, size, offset, original_offset);
3974
3975   return *offset - original_offset;
3976 }
3977
3978
3979 guint64
3980 atom_mfra_copy_data (AtomMFRA * mfra, guint8 ** buffer, guint64 * size,
3981     guint64 * offset)
3982 {
3983   guint64 original_offset = *offset;
3984   GList *walker;
3985
3986   if (!atom_copy_data (&mfra->header, buffer, size, offset))
3987     return 0;
3988
3989   walker = g_list_first (mfra->tfras);
3990   while (walker != NULL) {
3991     if (!atom_tfra_copy_data ((AtomTFRA *) walker->data, buffer, size, offset)) {
3992       return 0;
3993     }
3994     walker = g_list_next (walker);
3995   }
3996
3997   /* 16 is the size of the mfro atom */
3998   if (!atom_mfro_copy_data (*offset - original_offset + 16, buffer,
3999           size, offset))
4000     return 0;
4001
4002   atom_write_size (buffer, size, offset, original_offset);
4003   return *offset - original_offset;
4004 }
4005
4006 /* some sample description construction helpers */
4007
4008 AtomInfo *
4009 build_esds_extension (AtomTRAK * trak, guint8 object_type, guint8 stream_type,
4010     const GstBuffer * codec_data, guint32 avg_bitrate, guint32 max_bitrate)
4011 {
4012   guint32 track_id;
4013   AtomESDS *esds;
4014
4015   track_id = trak->tkhd.track_ID;
4016
4017   esds = atom_esds_new ();
4018   esds->es.id = track_id & 0xFFFF;
4019   esds->es.dec_conf_desc.object_type = object_type;
4020   esds->es.dec_conf_desc.stream_type = stream_type << 2 | 0x01;
4021
4022   if (avg_bitrate > 0)
4023     esds->es.dec_conf_desc.avg_bitrate = avg_bitrate;
4024   if (max_bitrate > 0)
4025     esds->es.dec_conf_desc.max_bitrate = max_bitrate;
4026
4027   /* optional DecoderSpecificInfo */
4028   if (codec_data) {
4029     DecoderSpecificInfoDescriptor *desc;
4030     gsize size;
4031
4032     esds->es.dec_conf_desc.dec_specific_info = desc =
4033         desc_dec_specific_info_new ();
4034     size = gst_buffer_get_size ((GstBuffer *) codec_data);
4035     desc_dec_specific_info_alloc_data (desc, size);
4036     gst_buffer_extract ((GstBuffer *) codec_data, 0, desc->data, size);
4037   }
4038
4039   return build_atom_info_wrapper ((Atom *) esds, atom_esds_copy_data,
4040       atom_esds_free);
4041 }
4042
4043 AtomInfo *
4044 build_btrt_extension (guint32 buffer_size_db, guint32 avg_bitrate,
4045     guint32 max_bitrate)
4046 {
4047   AtomData *atom_data;
4048   GstBuffer *buf;
4049   guint8 *data;
4050
4051   data = g_malloc (12);
4052   GST_WRITE_UINT32_BE (data, buffer_size_db);
4053   GST_WRITE_UINT32_BE (data + 4, max_bitrate);
4054   GST_WRITE_UINT32_BE (data + 8, avg_bitrate);
4055
4056   buf = _gst_buffer_new_wrapped (data, 12, g_free);
4057   atom_data = atom_data_new_from_gst_buffer (FOURCC_btrt, buf);
4058   gst_buffer_unref (buf);
4059
4060   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4061       atom_data_free);
4062 }
4063
4064 static AtomInfo *
4065 build_mov_wave_extension (AtomTRAK * trak, guint32 fourcc, AtomInfo * atom1,
4066     AtomInfo * atom2, gboolean terminator)
4067 {
4068   AtomWAVE *wave;
4069   AtomFRMA *frma;
4070   Atom *ext_atom;
4071
4072   /* Build WAVE atom for sample table entry */
4073   wave = atom_wave_new ();
4074
4075   /* Prepend Terminator atom to the WAVE list first, so it ends up last */
4076   if (terminator) {
4077     ext_atom = (Atom *) atom_data_new (FOURCC_null);
4078     wave->extension_atoms =
4079         atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
4080         (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
4081   }
4082
4083   /* Add supplied atoms to WAVE */
4084   if (atom2)
4085     wave->extension_atoms = g_list_prepend (wave->extension_atoms, atom2);
4086   if (atom1)
4087     wave->extension_atoms = g_list_prepend (wave->extension_atoms, atom1);
4088
4089   /* Add FRMA to the WAVE */
4090   frma = atom_frma_new ();
4091   frma->media_type = fourcc;
4092
4093   wave->extension_atoms =
4094       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
4095       (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
4096
4097   return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
4098       atom_wave_free);
4099 }
4100
4101 AtomInfo *
4102 build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data,
4103     guint32 avg_bitrate, guint32 max_bitrate)
4104 {
4105   AtomInfo *esds, *mp4a;
4106   GstBuffer *buf;
4107   guint32 tmp = 0;
4108
4109   /* Add ESDS atom to WAVE */
4110   esds = build_esds_extension (trak, ESDS_OBJECT_TYPE_MPEG4_P3,
4111       ESDS_STREAM_TYPE_AUDIO, codec_data, avg_bitrate, max_bitrate);
4112
4113   /* Add MP4A atom to the WAVE:
4114    * not really in spec, but makes offset based players happy */
4115   buf = _gst_buffer_new_wrapped (&tmp, 4, NULL);
4116   mp4a = build_codec_data_extension (FOURCC_mp4a, buf);
4117   gst_buffer_unref (buf);
4118
4119   return build_mov_wave_extension (trak, FOURCC_mp4a, mp4a, esds, TRUE);
4120 }
4121
4122 AtomInfo *
4123 build_mov_alac_extension (AtomTRAK * trak, const GstBuffer * codec_data)
4124 {
4125   AtomInfo *alac;
4126
4127   alac = build_codec_data_extension (FOURCC_alac, codec_data);
4128
4129   return build_mov_wave_extension (trak, FOURCC_alac, NULL, alac, TRUE);
4130 }
4131
4132 AtomInfo *
4133 build_fiel_extension (gint fields)
4134 {
4135   AtomData *atom_data;
4136   GstBuffer *buf;
4137   guint8 f = fields;
4138
4139   if (fields == 1) {
4140     return NULL;
4141   }
4142
4143   buf = _gst_buffer_new_wrapped (&f, 1, NULL);
4144   atom_data =
4145       atom_data_new_from_gst_buffer (GST_MAKE_FOURCC ('f', 'i', 'e', 'l'), buf);
4146   gst_buffer_unref (buf);
4147
4148   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4149       atom_data_free);
4150 }
4151
4152 AtomInfo *
4153 build_jp2x_extension (const GstBuffer * prefix)
4154 {
4155   AtomData *atom_data;
4156
4157   if (!prefix) {
4158     return NULL;
4159   }
4160
4161   atom_data =
4162       atom_data_new_from_gst_buffer (GST_MAKE_FOURCC ('j', 'p', '2', 'x'),
4163       prefix);
4164
4165   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4166       atom_data_free);
4167 }
4168
4169 AtomInfo *
4170 build_jp2h_extension (AtomTRAK * trak, gint width, gint height,
4171     const gchar * colorspace, gint ncomp, const GValue * cmap_array,
4172     const GValue * cdef_array)
4173 {
4174   AtomData *atom_data;
4175   GstBuffer *buf;
4176   guint8 cenum;
4177   gint i;
4178   gint idhr_size = 22;
4179   gint colr_size = 15;
4180   gint cmap_size = 0, cdef_size = 0;
4181   gint cmap_array_size = 0;
4182   gint cdef_array_size = 0;
4183   GstByteWriter writer;
4184
4185   g_return_val_if_fail (cmap_array == NULL ||
4186       GST_VALUE_HOLDS_ARRAY (cmap_array), NULL);
4187   g_return_val_if_fail (cdef_array == NULL ||
4188       GST_VALUE_HOLDS_ARRAY (cdef_array), NULL);
4189
4190   if (g_str_equal (colorspace, "sRGB")) {
4191     cenum = 0x10;
4192     if (ncomp == 0)
4193       ncomp = 3;
4194   } else if (g_str_equal (colorspace, "GRAY")) {
4195     cenum = 0x11;
4196     if (ncomp == 0)
4197       ncomp = 1;
4198   } else if (g_str_equal (colorspace, "sYUV")) {
4199     cenum = 0x12;
4200     if (ncomp == 0)
4201       ncomp = 3;
4202   } else
4203     return NULL;
4204
4205   if (cmap_array) {
4206     cmap_array_size = gst_value_array_get_size (cmap_array);
4207     cmap_size = 8 + cmap_array_size * 4;
4208   }
4209   if (cdef_array) {
4210     cdef_array_size = gst_value_array_get_size (cdef_array);
4211     cdef_size = 8 + 2 + cdef_array_size * 6;
4212   }
4213
4214   gst_byte_writer_init_with_size (&writer,
4215       idhr_size + colr_size + cmap_size + cdef_size, TRUE);
4216
4217   /* ihdr = image header box */
4218   gst_byte_writer_put_uint32_be (&writer, 22);
4219   gst_byte_writer_put_uint32_le (&writer, GST_MAKE_FOURCC ('i', 'h', 'd', 'r'));
4220   gst_byte_writer_put_uint32_be (&writer, height);
4221   gst_byte_writer_put_uint32_be (&writer, width);
4222   gst_byte_writer_put_uint16_be (&writer, ncomp);
4223   /* 8 bits per component, unsigned */
4224   gst_byte_writer_put_uint8 (&writer, 0x7);
4225   /* compression type; reserved */
4226   gst_byte_writer_put_uint8 (&writer, 0x7);
4227   /* colour space (un)known */
4228   gst_byte_writer_put_uint8 (&writer, 0x0);
4229   /* intellectual property right (box present) */
4230   gst_byte_writer_put_uint8 (&writer, 0x0);
4231
4232   /* colour specification box */
4233   gst_byte_writer_put_uint32_be (&writer, 15);
4234   gst_byte_writer_put_uint32_le (&writer, GST_MAKE_FOURCC ('c', 'o', 'l', 'r'));
4235
4236   /* specification method: enumerated */
4237   gst_byte_writer_put_uint8 (&writer, 0x1);
4238   /* precedence; reserved */
4239   gst_byte_writer_put_uint8 (&writer, 0x0);
4240   /* approximation; reserved */
4241   gst_byte_writer_put_uint8 (&writer, 0x0);
4242   /* enumerated colourspace */
4243   gst_byte_writer_put_uint32_be (&writer, cenum);
4244
4245   if (cmap_array) {
4246     gst_byte_writer_put_uint32_be (&writer, cmap_size);
4247     gst_byte_writer_put_uint32_le (&writer,
4248         GST_MAKE_FOURCC ('c', 'm', 'a', 'p'));
4249     for (i = 0; i < cmap_array_size; i++) {
4250       const GValue *item;
4251       gint value;
4252       guint16 cmp;
4253       guint8 mtyp;
4254       guint8 pcol;
4255       item = gst_value_array_get_value (cmap_array, i);
4256       value = g_value_get_int (item);
4257
4258       /* value is '(mtyp << 24) | (pcol << 16) | cmp' */
4259       cmp = value & 0xFFFF;
4260       mtyp = value >> 24;
4261       pcol = (value >> 16) & 0xFF;
4262
4263       if (mtyp == 1)
4264         GST_WARNING ("MTYP of cmap atom signals Pallete Mapping, but we don't "
4265             "handle Pallete mapping atoms yet");
4266
4267       gst_byte_writer_put_uint16_be (&writer, cmp);
4268       gst_byte_writer_put_uint8 (&writer, mtyp);
4269       gst_byte_writer_put_uint8 (&writer, pcol);
4270     }
4271   }
4272
4273   if (cdef_array) {
4274     gst_byte_writer_put_uint32_be (&writer, cdef_size);
4275     gst_byte_writer_put_uint32_le (&writer,
4276         GST_MAKE_FOURCC ('c', 'd', 'e', 'f'));
4277     gst_byte_writer_put_uint16_be (&writer, cdef_array_size);
4278     for (i = 0; i < cdef_array_size; i++) {
4279       const GValue *item;
4280       gint value;
4281       item = gst_value_array_get_value (cdef_array, i);
4282       value = g_value_get_int (item);
4283
4284       gst_byte_writer_put_uint16_be (&writer, i);
4285       if (value > 0) {
4286         gst_byte_writer_put_uint16_be (&writer, 0);
4287         gst_byte_writer_put_uint16_be (&writer, value);
4288       } else if (value < 0) {
4289         gst_byte_writer_put_uint16_be (&writer, -value);
4290         gst_byte_writer_put_uint16_be (&writer, 0);     /* TODO what here? */
4291       } else {
4292         gst_byte_writer_put_uint16_be (&writer, 1);
4293         gst_byte_writer_put_uint16_be (&writer, 0);
4294       }
4295     }
4296   }
4297
4298   g_assert (gst_byte_writer_get_remaining (&writer) == 0);
4299   buf = gst_byte_writer_reset_and_get_buffer (&writer);
4300
4301   atom_data = atom_data_new_from_gst_buffer (FOURCC_jp2h, buf);
4302   gst_buffer_unref (buf);
4303
4304   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4305       atom_data_free);
4306 }
4307
4308 AtomInfo *
4309 build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data)
4310 {
4311   AtomData *data;
4312   AtomInfo *result = NULL;
4313
4314   if (codec_data) {
4315     data = atom_data_new_from_gst_buffer (fourcc, codec_data);
4316     result = build_atom_info_wrapper ((Atom *) data, atom_data_copy_data,
4317         atom_data_free);
4318   }
4319
4320   return result;
4321 }
4322
4323 AtomInfo *
4324 build_amr_extension (void)
4325 {
4326   guint8 ext[9];
4327   GstBuffer *buf;
4328   AtomInfo *res;
4329
4330   /* vendor */
4331   GST_WRITE_UINT32_LE (ext, 0);
4332   /* decoder version */
4333   GST_WRITE_UINT8 (ext + 4, 0);
4334   /* mode set (all modes) */
4335   GST_WRITE_UINT16_BE (ext + 5, 0x81FF);
4336   /* mode change period (no restriction) */
4337   GST_WRITE_UINT8 (ext + 7, 0);
4338   /* frames per sample */
4339   GST_WRITE_UINT8 (ext + 8, 1);
4340
4341   buf = _gst_buffer_new_wrapped (ext, sizeof (ext), NULL);
4342   res = build_codec_data_extension (GST_MAKE_FOURCC ('d', 'a', 'm', 'r'), buf);
4343   gst_buffer_unref (buf);
4344   return res;
4345 }
4346
4347 AtomInfo *
4348 build_h263_extension (void)
4349 {
4350   guint8 ext[7];
4351   GstBuffer *buf;
4352   AtomInfo *res;
4353
4354   /* vendor */
4355   GST_WRITE_UINT32_LE (ext, 0);
4356   /* decoder version */
4357   GST_WRITE_UINT8 (ext + 4, 0);
4358   /* level / profile */
4359   /* FIXME ? maybe ? obtain somewhere; baseline for now */
4360   GST_WRITE_UINT8 (ext + 5, 10);
4361   GST_WRITE_UINT8 (ext + 6, 0);
4362
4363   buf = _gst_buffer_new_wrapped (ext, sizeof (ext), NULL);
4364   res = build_codec_data_extension (GST_MAKE_FOURCC ('d', '2', '6', '3'), buf);
4365   gst_buffer_unref (buf);
4366   return res;
4367 }
4368
4369 AtomInfo *
4370 build_gama_atom (gdouble gamma)
4371 {
4372   AtomInfo *res;
4373   guint32 gamma_fp;
4374   GstBuffer *buf;
4375
4376   /* convert to uint32 from fixed point */
4377   gamma_fp = (guint32) 65536 *gamma;
4378
4379   gamma_fp = GUINT32_TO_BE (gamma_fp);
4380   buf = _gst_buffer_new_wrapped (&gamma_fp, 4, NULL);
4381   res = build_codec_data_extension (FOURCC_gama, buf);
4382   gst_buffer_unref (buf);
4383   return res;
4384 }
4385
4386 AtomInfo *
4387 build_SMI_atom (const GstBuffer * seqh)
4388 {
4389   AtomInfo *res;
4390   GstBuffer *buf;
4391   gsize size;
4392   guint8 *data;
4393
4394   /* the seqh plus its size and fourcc */
4395   size = gst_buffer_get_size ((GstBuffer *) seqh);
4396   data = g_malloc (size + 8);
4397
4398   GST_WRITE_UINT32_LE (data, FOURCC_SEQH);
4399   GST_WRITE_UINT32_BE (data + 4, size + 8);
4400   gst_buffer_extract ((GstBuffer *) seqh, 0, data + 8, size);
4401   buf = _gst_buffer_new_wrapped (data, size + 8, g_free);
4402   res = build_codec_data_extension (FOURCC_SMI_, buf);
4403   gst_buffer_unref (buf);
4404   return res;
4405 }
4406
4407 static AtomInfo *
4408 build_ima_adpcm_atom (gint channels, gint rate, gint blocksize)
4409 {
4410   AtomData *atom_data;
4411   GstBuffer *buf;
4412   guint8 *data;
4413   const gint ima_adpcm_atom_size = 20;
4414   guint32 fourcc;
4415   gint samplesperblock;
4416   gint bytespersec;
4417
4418   /* The FOURCC for WAV codecs in QT is 'ms' followed by the 16 bit wave codec
4419      identifier. Note that the identifier here is big-endian, but when used
4420      within the WAVE header (below), it's little endian. */
4421   fourcc = MS_WAVE_FOURCC (0x11);
4422
4423   data = g_malloc (ima_adpcm_atom_size);
4424
4425   /* This atom's content is a WAVE header, including 2 bytes of extra data.
4426      Note that all of this is little-endian, unlike most stuff in qt. */
4427   /* 4 bytes header per channel (including 1 sample). Then 2 samples per byte
4428      for the rest. Simplifies to this. */
4429   samplesperblock = 2 * blocksize / channels - 7;
4430   bytespersec = rate * blocksize / samplesperblock;
4431   GST_WRITE_UINT16_LE (data, 0x11);
4432   GST_WRITE_UINT16_LE (data + 2, channels);
4433   GST_WRITE_UINT32_LE (data + 4, rate);
4434   GST_WRITE_UINT32_LE (data + 8, bytespersec);
4435   GST_WRITE_UINT16_LE (data + 12, blocksize);
4436   GST_WRITE_UINT16_LE (data + 14, 4);
4437   GST_WRITE_UINT16_LE (data + 16, 2);   /* Two extra bytes */
4438   GST_WRITE_UINT16_LE (data + 18, samplesperblock);
4439
4440   buf = _gst_buffer_new_wrapped (data, ima_adpcm_atom_size, g_free);
4441   atom_data = atom_data_new_from_gst_buffer (fourcc, buf);
4442   gst_buffer_unref (buf);
4443
4444   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4445       atom_data_free);
4446 }
4447
4448 AtomInfo *
4449 build_ima_adpcm_extension (gint channels, gint rate, gint blocksize)
4450 {
4451   AtomWAVE *wave;
4452   AtomFRMA *frma;
4453   Atom *ext_atom;
4454
4455   /* Add WAVE atom */
4456   wave = atom_wave_new ();
4457
4458   /* Prepend Terminator atom to the WAVE list first, so it ends up last */
4459   ext_atom = (Atom *) atom_data_new (FOURCC_null);
4460   wave->extension_atoms =
4461       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
4462       (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
4463
4464   /* Add wave ima adpcm atom to WAVE */
4465   wave->extension_atoms = g_list_prepend (wave->extension_atoms,
4466       build_ima_adpcm_atom (channels, rate, blocksize));
4467
4468   /* Add FRMA to the WAVE */
4469   frma = atom_frma_new ();
4470   frma->media_type = MS_WAVE_FOURCC (0x11);
4471
4472   wave->extension_atoms =
4473       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
4474       (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
4475
4476   return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
4477       atom_wave_free);
4478 }
4479
4480 AtomInfo *
4481 build_uuid_xmp_atom (GstBuffer * xmp_data)
4482 {
4483   AtomUUID *uuid;
4484   gsize size;
4485   static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
4486     0x97, 0xA9, 0x42, 0xE8,
4487     0x9C, 0x71, 0x99, 0x94,
4488     0x91, 0xE3, 0xAF, 0xAC
4489   };
4490
4491   if (xmp_data == NULL)
4492     return NULL;
4493
4494   uuid = atom_uuid_new ();
4495   memcpy (uuid->uuid, xmp_uuid, 16);
4496
4497   size = gst_buffer_get_size (xmp_data);
4498   uuid->data = g_malloc (size);
4499   uuid->datalen = size;
4500   gst_buffer_extract (xmp_data, 0, uuid->data, size);
4501
4502   return build_atom_info_wrapper ((Atom *) uuid, atom_uuid_copy_data,
4503       atom_uuid_free);
4504 }