splitmuxsink: Remove unused next_max_out_running_time
[platform/upstream/gst-plugins-good.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., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, 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 #include <gst/video/video.h>
52
53 /*
54  * Creates a new AtomsContext for the given flavor.
55  */
56 AtomsContext *
57 atoms_context_new (AtomsTreeFlavor flavor)
58 {
59   AtomsContext *context = g_new0 (AtomsContext, 1);
60   context->flavor = flavor;
61   return context;
62 }
63
64 /*
65  * Frees an AtomsContext and all memory associated with it
66  */
67 void
68 atoms_context_free (AtomsContext * context)
69 {
70   g_free (context);
71 }
72
73 /* -- creation, initialization, clear and free functions -- */
74
75 #define SECS_PER_DAY (24 * 60 * 60)
76 #define LEAP_YEARS_FROM_1904_TO_1970 17
77
78 static guint64
79 get_current_qt_time (void)
80 {
81   GTimeVal timeval;
82
83   g_get_current_time (&timeval);
84   /* FIXME this should use UTC coordinated time */
85   return timeval.tv_sec + (((1970 - 1904) * (guint64) 365) +
86       LEAP_YEARS_FROM_1904_TO_1970) * SECS_PER_DAY;
87 }
88
89 static void
90 common_time_info_init (TimeInfo * ti)
91 {
92   ti->creation_time = ti->modification_time = get_current_qt_time ();
93   ti->timescale = 0;
94   ti->duration = 0;
95 }
96
97 static void
98 atom_header_set (Atom * header, guint32 fourcc, gint32 size, gint64 ext_size)
99 {
100   header->type = fourcc;
101   header->size = size;
102   header->extended_size = ext_size;
103 }
104
105 static void
106 atom_clear (Atom * atom)
107 {
108 }
109
110 static void
111 atom_full_init (AtomFull * full, guint32 fourcc, gint32 size, gint64 ext_size,
112     guint8 version, guint8 flags[3])
113 {
114   atom_header_set (&(full->header), fourcc, size, ext_size);
115   full->version = version;
116   full->flags[0] = flags[0];
117   full->flags[1] = flags[1];
118   full->flags[2] = flags[2];
119 }
120
121 static void
122 atom_full_clear (AtomFull * full)
123 {
124   atom_clear (&full->header);
125 }
126
127 static void
128 atom_full_free (AtomFull * full)
129 {
130   atom_full_clear (full);
131   g_free (full);
132 }
133
134 static guint32
135 atom_full_get_flags_as_uint (AtomFull * full)
136 {
137   return full->flags[0] << 16 | full->flags[1] << 8 | full->flags[2];
138 }
139
140 static void
141 atom_full_set_flags_as_uint (AtomFull * full, guint32 flags_as_uint)
142 {
143   full->flags[2] = flags_as_uint & 0xFF;
144   full->flags[1] = (flags_as_uint & 0xFF00) >> 8;
145   full->flags[0] = (flags_as_uint & 0xFF0000) >> 16;
146 }
147
148 static AtomInfo *
149 build_atom_info_wrapper (Atom * atom, gpointer copy_func, gpointer free_func)
150 {
151   AtomInfo *info = NULL;
152
153   if (atom) {
154     info = g_new0 (AtomInfo, 1);
155
156     info->atom = atom;
157     info->copy_data_func = copy_func;
158     info->free_func = free_func;
159   }
160
161   return info;
162 }
163
164 static GList *
165 atom_info_list_prepend_atom (GList * ai, Atom * atom,
166     AtomCopyDataFunc copy_func, AtomFreeFunc free_func)
167 {
168   if (atom)
169     return g_list_prepend (ai,
170         build_atom_info_wrapper (atom, copy_func, free_func));
171   else
172     return ai;
173 }
174
175 static void
176 atom_info_list_free (GList * ai)
177 {
178   while (ai) {
179     AtomInfo *info = (AtomInfo *) ai->data;
180
181     info->free_func (info->atom);
182     g_free (info);
183     ai = g_list_delete_link (ai, ai);
184   }
185 }
186
187 static AtomData *
188 atom_data_new (guint32 fourcc)
189 {
190   AtomData *data = g_new0 (AtomData, 1);
191
192   atom_header_set (&data->header, fourcc, 0, 0);
193   return data;
194 }
195
196 static void
197 atom_data_alloc_mem (AtomData * data, guint32 size)
198 {
199   g_free (data->data);
200   data->data = g_new0 (guint8, size);
201   data->datalen = size;
202 }
203
204 static AtomData *
205 atom_data_new_from_data (guint32 fourcc, const guint8 * mem, gsize size)
206 {
207   AtomData *data = atom_data_new (fourcc);
208
209   atom_data_alloc_mem (data, size);
210   memcpy (data->data, mem, size);
211   return data;
212 }
213
214 static AtomData *
215 atom_data_new_from_gst_buffer (guint32 fourcc, const GstBuffer * buf)
216 {
217   AtomData *data = atom_data_new (fourcc);
218   gsize size = gst_buffer_get_size ((GstBuffer *) buf);
219
220   atom_data_alloc_mem (data, size);
221   gst_buffer_extract ((GstBuffer *) buf, 0, data->data, size);
222   return data;
223 }
224
225 static void
226 atom_data_free (AtomData * data)
227 {
228   atom_clear (&data->header);
229   g_free (data->data);
230   g_free (data);
231 }
232
233 static AtomUUID *
234 atom_uuid_new (void)
235 {
236   AtomUUID *uuid = g_new0 (AtomUUID, 1);
237
238   atom_header_set (&uuid->header, FOURCC_uuid, 0, 0);
239   return uuid;
240 }
241
242 static void
243 atom_uuid_free (AtomUUID * data)
244 {
245   atom_clear (&data->header);
246   g_free (data->data);
247   g_free (data);
248 }
249
250 static void
251 atom_ftyp_init (AtomFTYP * ftyp, guint32 major, guint32 version, GList * brands)
252 {
253   gint index;
254   GList *it = NULL;
255
256   atom_header_set (&ftyp->header, FOURCC_ftyp, 16, 0);
257   ftyp->major_brand = major;
258   ftyp->version = version;
259
260   /* always include major brand as compatible brand */
261   ftyp->compatible_brands_size = g_list_length (brands) + 1;
262   ftyp->compatible_brands = g_new (guint32, ftyp->compatible_brands_size);
263
264   ftyp->compatible_brands[0] = major;
265   index = 1;
266   for (it = brands; it != NULL; it = g_list_next (it)) {
267     ftyp->compatible_brands[index++] = GPOINTER_TO_UINT (it->data);
268   }
269 }
270
271 AtomFTYP *
272 atom_ftyp_new (AtomsContext * context, guint32 major, guint32 version,
273     GList * brands)
274 {
275   AtomFTYP *ftyp = g_new0 (AtomFTYP, 1);
276
277   atom_ftyp_init (ftyp, major, version, brands);
278   return ftyp;
279 }
280
281 void
282 atom_ftyp_free (AtomFTYP * ftyp)
283 {
284   atom_clear (&ftyp->header);
285   g_free (ftyp->compatible_brands);
286   ftyp->compatible_brands = NULL;
287   g_free (ftyp);
288 }
289
290 static void
291 atom_esds_init (AtomESDS * esds)
292 {
293   guint8 flags[3] = { 0, 0, 0 };
294
295   atom_full_init (&esds->header, FOURCC_esds, 0, 0, 0, flags);
296   desc_es_init (&esds->es);
297 }
298
299 static AtomESDS *
300 atom_esds_new (void)
301 {
302   AtomESDS *esds = g_new0 (AtomESDS, 1);
303
304   atom_esds_init (esds);
305   return esds;
306 }
307
308 static void
309 atom_esds_free (AtomESDS * esds)
310 {
311   atom_full_clear (&esds->header);
312   desc_es_descriptor_clear (&esds->es);
313   g_free (esds);
314 }
315
316 static AtomFRMA *
317 atom_frma_new (void)
318 {
319   AtomFRMA *frma = g_new0 (AtomFRMA, 1);
320
321   atom_header_set (&frma->header, FOURCC_frma, 0, 0);
322   return frma;
323 }
324
325 static void
326 atom_frma_free (AtomFRMA * frma)
327 {
328   atom_clear (&frma->header);
329   g_free (frma);
330 }
331
332 static AtomWAVE *
333 atom_wave_new (void)
334 {
335   AtomWAVE *wave = g_new0 (AtomWAVE, 1);
336
337   atom_header_set (&wave->header, FOURCC_wave, 0, 0);
338   return wave;
339 }
340
341 static void
342 atom_wave_free (AtomWAVE * wave)
343 {
344   atom_clear (&wave->header);
345   atom_info_list_free (wave->extension_atoms);
346   g_free (wave);
347 }
348
349 static void
350 atom_elst_init (AtomELST * elst)
351 {
352   guint8 flags[3] = { 0, 0, 0 };
353   atom_full_init (&elst->header, FOURCC_elst, 0, 0, 0, flags);
354   elst->entries = 0;
355 }
356
357 static void
358 atom_elst_clear (AtomELST * elst)
359 {
360   GSList *walker;
361
362   atom_full_clear (&elst->header);
363   walker = elst->entries;
364   while (walker) {
365     g_free ((EditListEntry *) walker->data);
366     walker = g_slist_next (walker);
367   }
368   g_slist_free (elst->entries);
369 }
370
371 static void
372 atom_edts_init (AtomEDTS * edts)
373 {
374   atom_header_set (&edts->header, FOURCC_edts, 0, 0);
375   atom_elst_init (&edts->elst);
376 }
377
378 static void
379 atom_edts_clear (AtomEDTS * edts)
380 {
381   atom_clear (&edts->header);
382   atom_elst_clear (&edts->elst);
383 }
384
385 static AtomEDTS *
386 atom_edts_new (void)
387 {
388   AtomEDTS *edts = g_new0 (AtomEDTS, 1);
389   atom_edts_init (edts);
390   return edts;
391 }
392
393 static void
394 atom_edts_free (AtomEDTS * edts)
395 {
396   atom_edts_clear (edts);
397   g_free (edts);
398 }
399
400 static void
401 atom_tcmi_init (AtomTCMI * tcmi)
402 {
403   guint8 flags[3] = { 0, 0, 0 };
404
405   atom_full_init (&tcmi->header, FOURCC_tcmi, 0, 0, 0, flags);
406 }
407
408 static void
409 atom_tcmi_clear (AtomTCMI * tcmi)
410 {
411   atom_full_clear (&tcmi->header);
412   tcmi->text_font = 0;
413   tcmi->text_face = 0;
414   tcmi->text_size = 0;
415   tcmi->text_color[0] = 0;
416   tcmi->text_color[1] = 0;
417   tcmi->text_color[2] = 0;
418   tcmi->bg_color[0] = 0;
419   tcmi->bg_color[1] = 0;
420   tcmi->bg_color[2] = 0;
421   g_free (tcmi->font_name);
422   tcmi->font_name = NULL;
423 }
424
425 static void
426 atom_tmcd_init (AtomTMCD * tmcd)
427 {
428   atom_header_set (&tmcd->header, FOURCC_tmcd, 0, 0);
429   atom_tcmi_init (&tmcd->tcmi);
430 }
431
432 static void
433 atom_tmcd_clear (AtomTMCD * tmcd)
434 {
435   atom_clear (&tmcd->header);
436   atom_tcmi_clear (&tmcd->tcmi);
437 }
438
439 static void
440 atom_gmin_init (AtomGMIN * gmin)
441 {
442   guint8 flags[3] = { 0, 0, 0 };
443
444   atom_full_init (&gmin->header, FOURCC_gmin, 0, 0, 0, flags);
445 }
446
447 static void
448 atom_gmin_clear (AtomGMIN * gmin)
449 {
450   atom_full_clear (&gmin->header);
451   gmin->graphics_mode = 0;
452   gmin->opcolor[0] = 0;
453   gmin->opcolor[1] = 0;
454   gmin->opcolor[2] = 0;
455   gmin->balance = 0;
456   gmin->reserved = 0;
457 }
458
459 static void
460 atom_gmhd_init (AtomGMHD * gmhd)
461 {
462   atom_header_set (&gmhd->header, FOURCC_gmhd, 0, 0);
463   atom_gmin_init (&gmhd->gmin);
464   atom_tmcd_init (&gmhd->tmcd);
465 }
466
467 static void
468 atom_gmhd_clear (AtomGMHD * gmhd)
469 {
470   atom_clear (&gmhd->header);
471   atom_gmin_clear (&gmhd->gmin);
472   atom_tmcd_clear (&gmhd->tmcd);
473 }
474
475 static AtomGMHD *
476 atom_gmhd_new (void)
477 {
478   AtomGMHD *gmhd = g_new0 (AtomGMHD, 1);
479   atom_gmhd_init (gmhd);
480   return gmhd;
481 }
482
483 static void
484 atom_gmhd_free (AtomGMHD * gmhd)
485 {
486   atom_gmhd_clear (gmhd);
487   g_free (gmhd);
488 }
489
490 static void
491 atom_sample_entry_init (SampleTableEntry * se, guint32 type)
492 {
493   atom_header_set (&se->header, type, 0, 0);
494
495   memset (se->reserved, 0, sizeof (guint8) * 6);
496   se->data_reference_index = 0;
497 }
498
499 static void
500 atom_sample_entry_free (SampleTableEntry * se)
501 {
502   atom_clear (&se->header);
503 }
504
505 static void
506 sample_entry_mp4a_init (SampleTableEntryMP4A * mp4a)
507 {
508   atom_sample_entry_init (&mp4a->se, FOURCC_mp4a);
509
510   mp4a->version = 0;
511   mp4a->revision_level = 0;
512   mp4a->vendor = 0;
513   mp4a->channels = 2;
514   mp4a->sample_size = 16;
515   mp4a->compression_id = 0;
516   mp4a->packet_size = 0;
517   mp4a->sample_rate = 0;
518   /* following only used if version is 1 */
519   mp4a->samples_per_packet = 0;
520   mp4a->bytes_per_packet = 0;
521   mp4a->bytes_per_frame = 0;
522   mp4a->bytes_per_sample = 0;
523
524   mp4a->extension_atoms = NULL;
525 }
526
527 static SampleTableEntryMP4A *
528 sample_entry_mp4a_new (void)
529 {
530   SampleTableEntryMP4A *mp4a = g_new0 (SampleTableEntryMP4A, 1);
531
532   sample_entry_mp4a_init (mp4a);
533   return mp4a;
534 }
535
536 static void
537 sample_entry_mp4a_free (SampleTableEntryMP4A * mp4a)
538 {
539   atom_sample_entry_free (&mp4a->se);
540   atom_info_list_free (mp4a->extension_atoms);
541   g_free (mp4a);
542 }
543
544 static void
545 sample_entry_tmcd_init (SampleTableEntryTMCD * tmcd)
546 {
547   atom_sample_entry_init (&tmcd->se, FOURCC_tmcd);
548
549   tmcd->tc_flags = 0;
550   tmcd->timescale = 0;
551   tmcd->frame_duration = 0;
552   tmcd->n_frames = 0;
553
554   tmcd->name.language_code = 0;
555   g_free (tmcd->name.name);
556   tmcd->name.name = NULL;
557 }
558
559 static SampleTableEntryTMCD *
560 sample_entry_tmcd_new (void)
561 {
562   SampleTableEntryTMCD *tmcd = g_new0 (SampleTableEntryTMCD, 1);
563
564   sample_entry_tmcd_init (tmcd);
565   return tmcd;
566 }
567
568 static void
569 sample_entry_mp4v_init (SampleTableEntryMP4V * mp4v, AtomsContext * context)
570 {
571   atom_sample_entry_init (&mp4v->se, FOURCC_mp4v);
572
573   mp4v->version = 0;
574   mp4v->revision_level = 0;
575   mp4v->vendor = 0;
576
577   mp4v->temporal_quality = 0;
578   mp4v->spatial_quality = 0;
579
580   /* qt and ISO base media do not contradict, and examples agree */
581   mp4v->horizontal_resolution = 0x00480000;
582   mp4v->vertical_resolution = 0x00480000;
583
584   mp4v->datasize = 0;
585   mp4v->frame_count = 1;
586
587   memset (mp4v->compressor, 0, sizeof (guint8) * 32);
588
589   mp4v->depth = 0;
590   mp4v->color_table_id = 0;
591
592   mp4v->extension_atoms = NULL;
593 }
594
595 static void
596 sample_entry_mp4v_free (SampleTableEntryMP4V * mp4v)
597 {
598   atom_sample_entry_free (&mp4v->se);
599   atom_info_list_free (mp4v->extension_atoms);
600   g_free (mp4v);
601 }
602
603 static SampleTableEntryMP4V *
604 sample_entry_mp4v_new (AtomsContext * context)
605 {
606   SampleTableEntryMP4V *mp4v = g_new0 (SampleTableEntryMP4V, 1);
607
608   sample_entry_mp4v_init (mp4v, context);
609   return mp4v;
610 }
611
612 static void
613 sample_entry_tx3g_init (SampleTableEntryTX3G * tx3g)
614 {
615   atom_sample_entry_init (&tx3g->se, FOURCC_tx3g);
616
617   tx3g->display_flags = 0;
618   tx3g->font_id = 1;            /* must be 1 as there is a single font */
619   tx3g->font_face = 0;
620   tx3g->foreground_color_rgba = 0xFFFFFFFF;     /* white, opaque */
621
622   /* can't set this now */
623   tx3g->default_text_box = 0;
624   tx3g->font_size = 0;
625 }
626
627 static void
628 sample_entry_tx3g_free (SampleTableEntryTX3G * tx3g)
629 {
630   atom_sample_entry_free (&tx3g->se);
631   g_free (tx3g);
632 }
633
634 static SampleTableEntryTX3G *
635 sample_entry_tx3g_new (void)
636 {
637   SampleTableEntryTX3G *tx3g = g_new0 (SampleTableEntryTX3G, 1);
638
639   sample_entry_tx3g_init (tx3g);
640   return tx3g;
641 }
642
643
644 static void
645 atom_stsd_init (AtomSTSD * stsd)
646 {
647   guint8 flags[3] = { 0, 0, 0 };
648
649   atom_full_init (&stsd->header, FOURCC_stsd, 0, 0, 0, flags);
650   stsd->entries = NULL;
651   stsd->n_entries = 0;
652 }
653
654 static void
655 atom_stsd_remove_entries (AtomSTSD * stsd)
656 {
657   GList *walker;
658
659   walker = stsd->entries;
660   while (walker) {
661     GList *aux = walker;
662     SampleTableEntry *se = (SampleTableEntry *) aux->data;
663
664     walker = g_list_next (walker);
665     stsd->entries = g_list_remove_link (stsd->entries, aux);
666
667     switch (se->kind) {
668       case AUDIO:
669         sample_entry_mp4a_free ((SampleTableEntryMP4A *) se);
670         break;
671       case VIDEO:
672         sample_entry_mp4v_free ((SampleTableEntryMP4V *) se);
673         break;
674       case SUBTITLE:
675         sample_entry_tx3g_free ((SampleTableEntryTX3G *) se);
676         break;
677       default:
678         /* best possible cleanup */
679         atom_sample_entry_free (se);
680     }
681     g_list_free (aux);
682   }
683   stsd->n_entries = 0;
684 }
685
686 static void
687 atom_stsd_clear (AtomSTSD * stsd)
688 {
689   atom_stsd_remove_entries (stsd);
690   atom_full_clear (&stsd->header);
691 }
692
693 static void
694 atom_ctts_init (AtomCTTS * ctts)
695 {
696   guint8 flags[3] = { 0, 0, 0 };
697
698   atom_full_init (&ctts->header, FOURCC_ctts, 0, 0, 0, flags);
699   atom_array_init (&ctts->entries, 128);
700   ctts->do_pts = FALSE;
701 }
702
703 static AtomCTTS *
704 atom_ctts_new (void)
705 {
706   AtomCTTS *ctts = g_new0 (AtomCTTS, 1);
707
708   atom_ctts_init (ctts);
709   return ctts;
710 }
711
712 static void
713 atom_ctts_free (AtomCTTS * ctts)
714 {
715   atom_full_clear (&ctts->header);
716   atom_array_clear (&ctts->entries);
717   g_free (ctts);
718 }
719
720 static void
721 atom_stts_init (AtomSTTS * stts)
722 {
723   guint8 flags[3] = { 0, 0, 0 };
724
725   atom_full_init (&stts->header, FOURCC_stts, 0, 0, 0, flags);
726   atom_array_init (&stts->entries, 512);
727 }
728
729 static void
730 atom_stts_clear (AtomSTTS * stts)
731 {
732   atom_full_clear (&stts->header);
733   atom_array_clear (&stts->entries);
734 }
735
736 static void
737 atom_stsz_init (AtomSTSZ * stsz)
738 {
739   guint8 flags[3] = { 0, 0, 0 };
740
741   atom_full_init (&stsz->header, FOURCC_stsz, 0, 0, 0, flags);
742   atom_array_init (&stsz->entries, 1024);
743   stsz->sample_size = 0;
744   stsz->table_size = 0;
745 }
746
747 static void
748 atom_stsz_clear (AtomSTSZ * stsz)
749 {
750   atom_full_clear (&stsz->header);
751   atom_array_clear (&stsz->entries);
752   stsz->table_size = 0;
753 }
754
755 static void
756 atom_stsc_init (AtomSTSC * stsc)
757 {
758   guint8 flags[3] = { 0, 0, 0 };
759
760   atom_full_init (&stsc->header, FOURCC_stsc, 0, 0, 0, flags);
761   atom_array_init (&stsc->entries, 128);
762 }
763
764 static void
765 atom_stsc_clear (AtomSTSC * stsc)
766 {
767   atom_full_clear (&stsc->header);
768   atom_array_clear (&stsc->entries);
769 }
770
771 static void
772 atom_co64_init (AtomSTCO64 * co64)
773 {
774   guint8 flags[3] = { 0, 0, 0 };
775
776   atom_full_init (&co64->header, FOURCC_stco, 0, 0, 0, flags);
777   atom_array_init (&co64->entries, 256);
778 }
779
780 static void
781 atom_stco64_clear (AtomSTCO64 * stco64)
782 {
783   atom_full_clear (&stco64->header);
784   atom_array_clear (&stco64->entries);
785 }
786
787 static void
788 atom_stss_init (AtomSTSS * stss)
789 {
790   guint8 flags[3] = { 0, 0, 0 };
791
792   atom_full_init (&stss->header, FOURCC_stss, 0, 0, 0, flags);
793   atom_array_init (&stss->entries, 128);
794 }
795
796 static void
797 atom_stss_clear (AtomSTSS * stss)
798 {
799   atom_full_clear (&stss->header);
800   atom_array_clear (&stss->entries);
801 }
802
803 void
804 atom_stbl_init (AtomSTBL * stbl)
805 {
806   atom_header_set (&stbl->header, FOURCC_stbl, 0, 0);
807
808   atom_stts_init (&stbl->stts);
809   atom_stss_init (&stbl->stss);
810   atom_stsd_init (&stbl->stsd);
811   atom_stsz_init (&stbl->stsz);
812   atom_stsc_init (&stbl->stsc);
813   stbl->ctts = NULL;
814
815   atom_co64_init (&stbl->stco64);
816 }
817
818 void
819 atom_stbl_clear (AtomSTBL * stbl)
820 {
821   atom_clear (&stbl->header);
822   atom_stsd_clear (&stbl->stsd);
823   atom_stts_clear (&stbl->stts);
824   atom_stss_clear (&stbl->stss);
825   atom_stsc_clear (&stbl->stsc);
826   atom_stsz_clear (&stbl->stsz);
827   if (stbl->ctts) {
828     atom_ctts_free (stbl->ctts);
829   }
830   atom_stco64_clear (&stbl->stco64);
831 }
832
833 static void
834 atom_vmhd_init (AtomVMHD * vmhd, AtomsContext * context)
835 {
836   guint8 flags[3] = { 0, 0, 1 };
837
838   atom_full_init (&vmhd->header, FOURCC_vmhd, 0, 0, 0, flags);
839   vmhd->graphics_mode = 0x0;
840   memset (vmhd->opcolor, 0, sizeof (guint16) * 3);
841
842   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
843     vmhd->graphics_mode = 0x40;
844     vmhd->opcolor[0] = 32768;
845     vmhd->opcolor[1] = 32768;
846     vmhd->opcolor[2] = 32768;
847   }
848 }
849
850 static AtomVMHD *
851 atom_vmhd_new (AtomsContext * context)
852 {
853   AtomVMHD *vmhd = g_new0 (AtomVMHD, 1);
854
855   atom_vmhd_init (vmhd, context);
856   return vmhd;
857 }
858
859 static void
860 atom_vmhd_free (AtomVMHD * vmhd)
861 {
862   atom_full_clear (&vmhd->header);
863   g_free (vmhd);
864 }
865
866 static void
867 atom_smhd_init (AtomSMHD * smhd)
868 {
869   guint8 flags[3] = { 0, 0, 0 };
870
871   atom_full_init (&smhd->header, FOURCC_smhd, 0, 0, 0, flags);
872   smhd->balance = 0;
873   smhd->reserved = 0;
874 }
875
876 static AtomSMHD *
877 atom_smhd_new (void)
878 {
879   AtomSMHD *smhd = g_new0 (AtomSMHD, 1);
880
881   atom_smhd_init (smhd);
882   return smhd;
883 }
884
885 static void
886 atom_smhd_free (AtomSMHD * smhd)
887 {
888   atom_full_clear (&smhd->header);
889   g_free (smhd);
890 }
891
892 static void
893 atom_hmhd_free (AtomHMHD * hmhd)
894 {
895   atom_full_clear (&hmhd->header);
896   g_free (hmhd);
897 }
898
899 static void
900 atom_hdlr_init (AtomHDLR * hdlr, AtomsContext * context)
901 {
902   guint8 flags[3] = { 0, 0, 0 };
903
904   atom_full_init (&hdlr->header, FOURCC_hdlr, 0, 0, 0, flags);
905
906   hdlr->component_type = 0;
907   hdlr->handler_type = 0;
908   hdlr->manufacturer = 0;
909   hdlr->flags = 0;
910   hdlr->flags_mask = 0;
911   hdlr->name = g_strdup ("");
912
913   /* Store the flavor to know how to serialize the 'name' string */
914   hdlr->flavor = context->flavor;
915 }
916
917 static AtomHDLR *
918 atom_hdlr_new (AtomsContext * context)
919 {
920   AtomHDLR *hdlr = g_new0 (AtomHDLR, 1);
921
922   atom_hdlr_init (hdlr, context);
923   return hdlr;
924 }
925
926 static void
927 atom_hdlr_clear (AtomHDLR * hdlr)
928 {
929   atom_full_clear (&hdlr->header);
930   if (hdlr->name) {
931     g_free (hdlr->name);
932     hdlr->name = NULL;
933   }
934 }
935
936 static void
937 atom_hdlr_free (AtomHDLR * hdlr)
938 {
939   atom_hdlr_clear (hdlr);
940   g_free (hdlr);
941 }
942
943 static void
944 atom_url_init (AtomURL * url)
945 {
946   guint8 flags[3] = { 0, 0, 1 };
947
948   atom_full_init (&url->header, FOURCC_url_, 0, 0, 0, flags);
949   url->location = NULL;
950 }
951
952 static void
953 atom_url_free (AtomURL * url)
954 {
955   atom_full_clear (&url->header);
956   if (url->location) {
957     g_free (url->location);
958     url->location = NULL;
959   }
960   g_free (url);
961 }
962
963 static AtomURL *
964 atom_url_new (void)
965 {
966   AtomURL *url = g_new0 (AtomURL, 1);
967
968   atom_url_init (url);
969   return url;
970 }
971
972 static AtomFull *
973 atom_alis_new (void)
974 {
975   guint8 flags[3] = { 0, 0, 1 };
976   AtomFull *alis = g_new0 (AtomFull, 1);
977
978   atom_full_init (alis, FOURCC_alis, 0, 0, 0, flags);
979   return alis;
980 }
981
982 static void
983 atom_dref_init (AtomDREF * dref, AtomsContext * context)
984 {
985   guint8 flags[3] = { 0, 0, 0 };
986
987   atom_full_init (&dref->header, FOURCC_dref, 0, 0, 0, flags);
988
989   /* in either case, alis or url init arranges to set self-contained flag */
990   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
991     /* alis dref for qt */
992     AtomFull *alis = atom_alis_new ();
993     dref->entries = g_list_append (dref->entries, alis);
994   } else {
995     /* url for iso spec, as 'alis' not specified there */
996     AtomURL *url = atom_url_new ();
997     dref->entries = g_list_append (dref->entries, url);
998   }
999 }
1000
1001 static void
1002 atom_dref_clear (AtomDREF * dref)
1003 {
1004   GList *walker;
1005
1006   atom_full_clear (&dref->header);
1007   walker = dref->entries;
1008   while (walker) {
1009     GList *aux = walker;
1010     Atom *atom = (Atom *) aux->data;
1011
1012     walker = g_list_next (walker);
1013     dref->entries = g_list_remove_link (dref->entries, aux);
1014     switch (atom->type) {
1015       case FOURCC_alis:
1016         atom_full_free ((AtomFull *) atom);
1017         break;
1018       case FOURCC_url_:
1019         atom_url_free ((AtomURL *) atom);
1020         break;
1021       default:
1022         /* we do nothing, better leak than crash */
1023         break;
1024     }
1025     g_list_free (aux);
1026   }
1027 }
1028
1029 static void
1030 atom_dinf_init (AtomDINF * dinf, AtomsContext * context)
1031 {
1032   atom_header_set (&dinf->header, FOURCC_dinf, 0, 0);
1033   atom_dref_init (&dinf->dref, context);
1034 }
1035
1036 static void
1037 atom_dinf_clear (AtomDINF * dinf)
1038 {
1039   atom_clear (&dinf->header);
1040   atom_dref_clear (&dinf->dref);
1041 }
1042
1043 static void
1044 atom_minf_init (AtomMINF * minf, AtomsContext * context)
1045 {
1046   atom_header_set (&minf->header, FOURCC_minf, 0, 0);
1047
1048   minf->vmhd = NULL;
1049   minf->smhd = NULL;
1050   minf->hmhd = NULL;
1051   minf->gmhd = NULL;
1052
1053   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
1054     minf->hdlr = atom_hdlr_new (context);
1055     minf->hdlr->component_type = FOURCC_dhlr;
1056     minf->hdlr->handler_type = FOURCC_alis;
1057   } else {
1058     minf->hdlr = NULL;
1059   }
1060   atom_dinf_init (&minf->dinf, context);
1061   atom_stbl_init (&minf->stbl);
1062 }
1063
1064 static void
1065 atom_minf_clear_handlers (AtomMINF * minf)
1066 {
1067   if (minf->vmhd) {
1068     atom_vmhd_free (minf->vmhd);
1069     minf->vmhd = NULL;
1070   }
1071   if (minf->smhd) {
1072     atom_smhd_free (minf->smhd);
1073     minf->smhd = NULL;
1074   }
1075   if (minf->hmhd) {
1076     atom_hmhd_free (minf->hmhd);
1077     minf->hmhd = NULL;
1078   }
1079   if (minf->gmhd) {
1080     atom_gmhd_free (minf->gmhd);
1081     minf->gmhd = NULL;
1082   }
1083 }
1084
1085 static void
1086 atom_minf_clear (AtomMINF * minf)
1087 {
1088   atom_clear (&minf->header);
1089   atom_minf_clear_handlers (minf);
1090   if (minf->hdlr) {
1091     atom_hdlr_free (minf->hdlr);
1092   }
1093   atom_dinf_clear (&minf->dinf);
1094   atom_stbl_clear (&minf->stbl);
1095 }
1096
1097 static void
1098 atom_mdhd_init (AtomMDHD * mdhd)
1099 {
1100   guint8 flags[3] = { 0, 0, 0 };
1101
1102   atom_full_init (&mdhd->header, FOURCC_mdhd, 0, 0, 0, flags);
1103   common_time_info_init (&mdhd->time_info);
1104   mdhd->language_code = 0;
1105   mdhd->quality = 0;
1106 }
1107
1108 static void
1109 atom_mdhd_clear (AtomMDHD * mdhd)
1110 {
1111   atom_full_clear (&mdhd->header);
1112 }
1113
1114 static void
1115 atom_mdia_init (AtomMDIA * mdia, AtomsContext * context)
1116 {
1117   atom_header_set (&mdia->header, FOURCC_mdia, 0, 0);
1118
1119   atom_mdhd_init (&mdia->mdhd);
1120   atom_hdlr_init (&mdia->hdlr, context);
1121   atom_minf_init (&mdia->minf, context);
1122 }
1123
1124 static void
1125 atom_mdia_clear (AtomMDIA * mdia)
1126 {
1127   atom_clear (&mdia->header);
1128   atom_mdhd_clear (&mdia->mdhd);
1129   atom_hdlr_clear (&mdia->hdlr);
1130   atom_minf_clear (&mdia->minf);
1131 }
1132
1133 static void
1134 atom_tkhd_init (AtomTKHD * tkhd, AtomsContext * context)
1135 {
1136   /*
1137    * flags info
1138    * 1 -> track enabled
1139    * 2 -> track in movie
1140    * 4 -> track in preview
1141    */
1142   guint8 flags[3] = { 0, 0, 7 };
1143
1144   atom_full_init (&tkhd->header, FOURCC_tkhd, 0, 0, 0, flags);
1145
1146   tkhd->creation_time = tkhd->modification_time = get_current_qt_time ();
1147   tkhd->duration = 0;
1148   tkhd->track_ID = 0;
1149   tkhd->reserved = 0;
1150
1151   tkhd->reserved2[0] = tkhd->reserved2[1] = 0;
1152   tkhd->layer = 0;
1153   tkhd->alternate_group = 0;
1154   tkhd->volume = 0;
1155   tkhd->reserved3 = 0;
1156   memset (tkhd->matrix, 0, sizeof (guint32) * 9);
1157   tkhd->matrix[0] = 1 << 16;
1158   tkhd->matrix[4] = 1 << 16;
1159   tkhd->matrix[8] = 16384 << 16;
1160   tkhd->width = 0;
1161   tkhd->height = 0;
1162 }
1163
1164 static void
1165 atom_tkhd_clear (AtomTKHD * tkhd)
1166 {
1167   atom_full_clear (&tkhd->header);
1168 }
1169
1170 static void
1171 atom_ilst_init (AtomILST * ilst)
1172 {
1173   atom_header_set (&ilst->header, FOURCC_ilst, 0, 0);
1174   ilst->entries = NULL;
1175 }
1176
1177 static AtomILST *
1178 atom_ilst_new (void)
1179 {
1180   AtomILST *ilst = g_new0 (AtomILST, 1);
1181
1182   atom_ilst_init (ilst);
1183   return ilst;
1184 }
1185
1186 static void
1187 atom_ilst_free (AtomILST * ilst)
1188 {
1189   if (ilst->entries)
1190     atom_info_list_free (ilst->entries);
1191   atom_clear (&ilst->header);
1192   g_free (ilst);
1193 }
1194
1195 static void
1196 atom_meta_init (AtomMETA * meta, AtomsContext * context)
1197 {
1198   guint8 flags[3] = { 0, 0, 0 };
1199
1200   atom_full_init (&meta->header, FOURCC_meta, 0, 0, 0, flags);
1201   atom_hdlr_init (&meta->hdlr, context);
1202   /* FIXME (ISOM says this is always 0) */
1203   meta->hdlr.component_type = FOURCC_mhlr;
1204   meta->hdlr.handler_type = FOURCC_mdir;
1205   meta->ilst = NULL;
1206 }
1207
1208 static AtomMETA *
1209 atom_meta_new (AtomsContext * context)
1210 {
1211   AtomMETA *meta = g_new0 (AtomMETA, 1);
1212
1213   atom_meta_init (meta, context);
1214   return meta;
1215 }
1216
1217 static void
1218 atom_meta_free (AtomMETA * meta)
1219 {
1220   atom_full_clear (&meta->header);
1221   atom_hdlr_clear (&meta->hdlr);
1222   if (meta->ilst)
1223     atom_ilst_free (meta->ilst);
1224   meta->ilst = NULL;
1225   g_free (meta);
1226 }
1227
1228 static void
1229 atom_udta_init_metatags (AtomUDTA * udta, AtomsContext * context)
1230 {
1231   if (context->flavor != ATOMS_TREE_FLAVOR_3GP) {
1232     if (!udta->meta) {
1233       udta->meta = atom_meta_new (context);
1234     }
1235     if (!udta->meta->ilst) {
1236       udta->meta->ilst = atom_ilst_new ();
1237     }
1238   }
1239 }
1240
1241 static void
1242 atom_udta_init (AtomUDTA * udta, AtomsContext * context)
1243 {
1244   atom_header_set (&udta->header, FOURCC_udta, 0, 0);
1245   udta->meta = NULL;
1246   udta->context = context;
1247
1248   atom_udta_init_metatags (udta, context);
1249 }
1250
1251 static void
1252 atom_udta_clear (AtomUDTA * udta)
1253 {
1254   atom_clear (&udta->header);
1255   if (udta->meta)
1256     atom_meta_free (udta->meta);
1257   udta->meta = NULL;
1258   if (udta->entries)
1259     atom_info_list_free (udta->entries);
1260 }
1261
1262 static void
1263 atom_tref_init (AtomTREF * tref, guint32 reftype)
1264 {
1265   atom_header_set (&tref->header, FOURCC_tref, 0, 0);
1266   tref->reftype = reftype;
1267   atom_array_init (&tref->entries, 128);
1268 }
1269
1270 static void
1271 atom_tref_clear (AtomTREF * tref)
1272 {
1273   atom_clear (&tref->header);
1274   tref->reftype = 0;
1275   atom_array_clear (&tref->entries);
1276 }
1277
1278 AtomTREF *
1279 atom_tref_new (guint32 reftype)
1280 {
1281   AtomTREF *tref;
1282
1283   tref = g_new0 (AtomTREF, 1);
1284   atom_tref_init (tref, reftype);
1285
1286   return tref;
1287 }
1288
1289 static void
1290 atom_tref_free (AtomTREF * tref)
1291 {
1292   atom_tref_clear (tref);
1293   g_free (tref);
1294 }
1295
1296 /* Clear added tags, but keep the context/flavor the same */
1297 void
1298 atom_udta_clear_tags (AtomUDTA * udta)
1299 {
1300   if (udta->entries) {
1301     atom_info_list_free (udta->entries);
1302     udta->entries = NULL;
1303   }
1304   if (udta->meta && udta->meta->ilst->entries) {
1305     atom_info_list_free (udta->meta->ilst->entries);
1306     udta->meta->ilst->entries = NULL;
1307   }
1308 }
1309
1310 static void
1311 atom_tag_data_init (AtomTagData * data)
1312 {
1313   guint8 flags[] = { 0, 0, 0 };
1314
1315   atom_full_init (&data->header, FOURCC_data, 0, 0, 0, flags);
1316 }
1317
1318 static void
1319 atom_tag_data_clear (AtomTagData * data)
1320 {
1321   atom_full_clear (&data->header);
1322   g_free (data->data);
1323   data->datalen = 0;
1324 }
1325
1326 /*
1327  * Fourcc is the tag fourcc
1328  * flags will be truncated to 24bits
1329  */
1330 static AtomTag *
1331 atom_tag_new (guint32 fourcc, guint32 flags_as_uint)
1332 {
1333   AtomTag *tag = g_new0 (AtomTag, 1);
1334
1335   tag->header.type = fourcc;
1336   atom_tag_data_init (&tag->data);
1337   atom_full_set_flags_as_uint (&tag->data.header, flags_as_uint);
1338   return tag;
1339 }
1340
1341 static void
1342 atom_tag_free (AtomTag * tag)
1343 {
1344   atom_clear (&tag->header);
1345   atom_tag_data_clear (&tag->data);
1346   g_free (tag);
1347 }
1348
1349 static void
1350 atom_mvhd_init (AtomMVHD * mvhd)
1351 {
1352   guint8 flags[3] = { 0, 0, 0 };
1353
1354   atom_full_init (&(mvhd->header), FOURCC_mvhd, sizeof (AtomMVHD), 0, 0, flags);
1355
1356   common_time_info_init (&mvhd->time_info);
1357
1358   mvhd->prefered_rate = 1 << 16;
1359   mvhd->volume = 1 << 8;
1360   mvhd->reserved3 = 0;
1361   memset (mvhd->reserved4, 0, sizeof (guint32[2]));
1362
1363   memset (mvhd->matrix, 0, sizeof (guint32[9]));
1364   mvhd->matrix[0] = 1 << 16;
1365   mvhd->matrix[4] = 1 << 16;
1366   mvhd->matrix[8] = 16384 << 16;
1367
1368   mvhd->preview_time = 0;
1369   mvhd->preview_duration = 0;
1370   mvhd->poster_time = 0;
1371   mvhd->selection_time = 0;
1372   mvhd->selection_duration = 0;
1373   mvhd->current_time = 0;
1374
1375   mvhd->next_track_id = 1;
1376 }
1377
1378 static void
1379 atom_mvhd_clear (AtomMVHD * mvhd)
1380 {
1381   atom_full_clear (&mvhd->header);
1382 }
1383
1384 static void
1385 atom_mehd_init (AtomMEHD * mehd)
1386 {
1387   guint8 flags[3] = { 0, 0, 0 };
1388
1389   atom_full_init (&mehd->header, FOURCC_mehd, 0, 0, 1, flags);
1390   mehd->fragment_duration = 0;
1391 }
1392
1393 static void
1394 atom_mvex_init (AtomMVEX * mvex)
1395 {
1396   atom_header_set (&mvex->header, FOURCC_mvex, 0, 0);
1397   atom_mehd_init (&mvex->mehd);
1398   mvex->trexs = NULL;
1399 }
1400
1401 static void
1402 atom_trak_init (AtomTRAK * trak, AtomsContext * context)
1403 {
1404   atom_header_set (&trak->header, FOURCC_trak, 0, 0);
1405
1406   atom_tkhd_init (&trak->tkhd, context);
1407   trak->context = context;
1408   atom_udta_init (&trak->udta, context);
1409   trak->edts = NULL;
1410   atom_mdia_init (&trak->mdia, context);
1411   trak->tref = NULL;
1412 }
1413
1414 AtomTRAK *
1415 atom_trak_new (AtomsContext * context)
1416 {
1417   AtomTRAK *trak = g_new0 (AtomTRAK, 1);
1418
1419   atom_trak_init (trak, context);
1420   return trak;
1421 }
1422
1423 static void
1424 atom_trak_clear (AtomTRAK * trak)
1425 {
1426   atom_clear (&trak->header);
1427   atom_tkhd_clear (&trak->tkhd);
1428   if (trak->edts)
1429     atom_edts_free (trak->edts);
1430   atom_udta_clear (&trak->udta);
1431   atom_mdia_clear (&trak->mdia);
1432   if (trak->tref)
1433     atom_tref_free (trak->tref);
1434 }
1435
1436 static void
1437 atom_trak_free (AtomTRAK * trak)
1438 {
1439   atom_trak_clear (trak);
1440   g_free (trak);
1441 }
1442
1443
1444 static void
1445 atom_moov_init (AtomMOOV * moov, AtomsContext * context)
1446 {
1447   atom_header_set (&(moov->header), FOURCC_moov, 0, 0);
1448   atom_mvhd_init (&(moov->mvhd));
1449   atom_mvex_init (&(moov->mvex));
1450   atom_udta_init (&moov->udta, context);
1451   moov->traks = NULL;
1452   moov->context = *context;
1453 }
1454
1455 AtomMOOV *
1456 atom_moov_new (AtomsContext * context)
1457 {
1458   AtomMOOV *moov = g_new0 (AtomMOOV, 1);
1459
1460   atom_moov_init (moov, context);
1461   return moov;
1462 }
1463
1464 static void
1465 atom_trex_free (AtomTREX * trex)
1466 {
1467   atom_full_clear (&trex->header);
1468   g_free (trex);
1469 }
1470
1471 static void
1472 atom_mvex_clear (AtomMVEX * mvex)
1473 {
1474   GList *walker;
1475
1476   atom_clear (&mvex->header);
1477   walker = mvex->trexs;
1478   while (walker) {
1479     atom_trex_free ((AtomTREX *) walker->data);
1480     walker = g_list_next (walker);
1481   }
1482   g_list_free (mvex->trexs);
1483   mvex->trexs = NULL;
1484 }
1485
1486 void
1487 atom_moov_free (AtomMOOV * moov)
1488 {
1489   GList *walker;
1490
1491   atom_clear (&moov->header);
1492   atom_mvhd_clear (&moov->mvhd);
1493
1494   walker = moov->traks;
1495   while (walker) {
1496     atom_trak_free ((AtomTRAK *) walker->data);
1497     walker = g_list_next (walker);
1498   }
1499   g_list_free (moov->traks);
1500   moov->traks = NULL;
1501
1502   atom_udta_clear (&moov->udta);
1503   atom_mvex_clear (&moov->mvex);
1504
1505   g_free (moov);
1506 }
1507
1508 /* -- end of init / free -- */
1509
1510 /* -- copy data functions -- */
1511
1512 static guint8
1513 atom_full_get_version (AtomFull * full)
1514 {
1515   return full->version;
1516 }
1517
1518 static guint64
1519 common_time_info_copy_data (TimeInfo * ti, gboolean trunc_to_32,
1520     guint8 ** buffer, guint64 * size, guint64 * offset)
1521 {
1522   guint64 original_offset = *offset;
1523
1524   if (trunc_to_32) {
1525     prop_copy_uint32 ((guint32) ti->creation_time, buffer, size, offset);
1526     prop_copy_uint32 ((guint32) ti->modification_time, buffer, size, offset);
1527     prop_copy_uint32 (ti->timescale, buffer, size, offset);
1528     prop_copy_uint32 ((guint32) ti->duration, buffer, size, offset);
1529   } else {
1530     prop_copy_uint64 (ti->creation_time, buffer, size, offset);
1531     prop_copy_uint64 (ti->modification_time, buffer, size, offset);
1532     prop_copy_uint32 (ti->timescale, buffer, size, offset);
1533     prop_copy_uint64 (ti->duration, buffer, size, offset);
1534   }
1535   return *offset - original_offset;
1536 }
1537
1538 static void
1539 atom_write_size (guint8 ** buffer, guint64 * size, guint64 * offset,
1540     guint64 atom_pos)
1541 {
1542   /* this only works for non-extended atom size, which is OK
1543    * (though it could be made to do mem_move, etc and write extended size) */
1544   prop_copy_uint32 (*offset - atom_pos, buffer, size, &atom_pos);
1545 }
1546
1547 static guint64
1548 atom_copy_empty (Atom * atom, guint8 ** buffer, guint64 * size,
1549     guint64 * offset)
1550 {
1551   guint64 original_offset = *offset;
1552
1553   prop_copy_uint32 (0, buffer, size, offset);
1554
1555   return *offset - original_offset;
1556 }
1557
1558 guint64
1559 atom_copy_data (Atom * atom, guint8 ** buffer, guint64 * size, guint64 * offset)
1560 {
1561   guint64 original_offset = *offset;
1562
1563   /* copies type and size */
1564   prop_copy_uint32 (atom->size, buffer, size, offset);
1565   prop_copy_fourcc (atom->type, buffer, size, offset);
1566
1567   /* extended size needed */
1568   if (atom->size == 1) {
1569     /* really should not happen other than with mdat atom;
1570      * would be a problem for size (re)write code, not to mention memory */
1571     g_return_val_if_fail (atom->type == FOURCC_mdat, 0);
1572     prop_copy_uint64 (atom->extended_size, buffer, size, offset);
1573   }
1574
1575   return *offset - original_offset;
1576 }
1577
1578 static guint64
1579 atom_full_copy_data (AtomFull * atom, guint8 ** buffer, guint64 * size,
1580     guint64 * offset)
1581 {
1582   guint64 original_offset = *offset;
1583
1584   if (!atom_copy_data (&atom->header, buffer, size, offset)) {
1585     return 0;
1586   }
1587
1588   prop_copy_uint8 (atom->version, buffer, size, offset);
1589   prop_copy_uint8_array (atom->flags, 3, buffer, size, offset);
1590
1591   atom_write_size (buffer, size, offset, original_offset);
1592   return *offset - original_offset;
1593 }
1594
1595 static guint64
1596 atom_info_list_copy_data (GList * ai, guint8 ** buffer, guint64 * size,
1597     guint64 * offset)
1598 {
1599   guint64 original_offset = *offset;
1600
1601   while (ai) {
1602     AtomInfo *info = (AtomInfo *) ai->data;
1603
1604     if (!info->copy_data_func (info->atom, buffer, size, offset)) {
1605       return 0;
1606     }
1607     ai = g_list_next (ai);
1608   }
1609
1610   return *offset - original_offset;
1611 }
1612
1613 static guint64
1614 atom_data_copy_data (AtomData * data, guint8 ** buffer, guint64 * size,
1615     guint64 * offset)
1616 {
1617   guint64 original_offset = *offset;
1618
1619   if (!atom_copy_data (&data->header, buffer, size, offset)) {
1620     return 0;
1621   }
1622   if (data->datalen)
1623     prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
1624
1625   atom_write_size (buffer, size, offset, original_offset);
1626   return *offset - original_offset;
1627 }
1628
1629 static guint64
1630 atom_uuid_copy_data (AtomUUID * uuid, guint8 ** buffer, guint64 * size,
1631     guint64 * offset)
1632 {
1633   guint64 original_offset = *offset;
1634
1635   if (!atom_copy_data (&uuid->header, buffer, size, offset)) {
1636     return 0;
1637   }
1638   prop_copy_uint8_array (uuid->uuid, 16, buffer, size, offset);
1639   if (uuid->datalen)
1640     prop_copy_uint8_array (uuid->data, uuid->datalen, buffer, size, offset);
1641
1642   atom_write_size (buffer, size, offset, original_offset);
1643   return *offset - original_offset;
1644 }
1645
1646 guint64
1647 atom_ftyp_copy_data (AtomFTYP * ftyp, guint8 ** buffer, guint64 * size,
1648     guint64 * offset)
1649 {
1650   guint64 original_offset = *offset;
1651
1652   if (!atom_copy_data (&ftyp->header, buffer, size, offset)) {
1653     return 0;
1654   }
1655   prop_copy_fourcc (ftyp->major_brand, buffer, size, offset);
1656   prop_copy_uint32 (ftyp->version, buffer, size, offset);
1657
1658   prop_copy_fourcc_array (ftyp->compatible_brands, ftyp->compatible_brands_size,
1659       buffer, size, offset);
1660
1661   atom_write_size (buffer, size, offset, original_offset);
1662   return *offset - original_offset;
1663 }
1664
1665 guint64
1666 atom_mvhd_copy_data (AtomMVHD * atom, guint8 ** buffer, guint64 * size,
1667     guint64 * offset)
1668 {
1669   guint8 version;
1670   guint64 original_offset = *offset;
1671
1672   if (!atom_full_copy_data (&(atom->header), buffer, size, offset)) {
1673     return 0;
1674   }
1675
1676   version = atom_full_get_version (&(atom->header));
1677   if (version == 0) {
1678     common_time_info_copy_data (&atom->time_info, TRUE, buffer, size, offset);
1679   } else if (version == 1) {
1680     common_time_info_copy_data (&atom->time_info, FALSE, buffer, size, offset);
1681   } else {
1682     *offset = original_offset;
1683     return 0;
1684   }
1685
1686   prop_copy_uint32 (atom->prefered_rate, buffer, size, offset);
1687   prop_copy_uint16 (atom->volume, buffer, size, offset);
1688   prop_copy_uint16 (atom->reserved3, buffer, size, offset);
1689   prop_copy_uint32_array (atom->reserved4, 2, buffer, size, offset);
1690   prop_copy_uint32_array (atom->matrix, 9, buffer, size, offset);
1691   prop_copy_uint32 (atom->preview_time, buffer, size, offset);
1692   prop_copy_uint32 (atom->preview_duration, buffer, size, offset);
1693   prop_copy_uint32 (atom->poster_time, buffer, size, offset);
1694   prop_copy_uint32 (atom->selection_time, buffer, size, offset);
1695   prop_copy_uint32 (atom->selection_duration, buffer, size, offset);
1696   prop_copy_uint32 (atom->current_time, buffer, size, offset);
1697
1698   prop_copy_uint32 (atom->next_track_id, buffer, size, offset);
1699
1700   atom_write_size (buffer, size, offset, original_offset);
1701   return *offset - original_offset;
1702 }
1703
1704 static guint64
1705 atom_tkhd_copy_data (AtomTKHD * tkhd, guint8 ** buffer, guint64 * size,
1706     guint64 * offset)
1707 {
1708   guint64 original_offset = *offset;
1709
1710   if (!atom_full_copy_data (&tkhd->header, buffer, size, offset)) {
1711     return 0;
1712   }
1713
1714   if (atom_full_get_version (&tkhd->header) == 0) {
1715     prop_copy_uint32 ((guint32) tkhd->creation_time, buffer, size, offset);
1716     prop_copy_uint32 ((guint32) tkhd->modification_time, buffer, size, offset);
1717     prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
1718     prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
1719     prop_copy_uint32 ((guint32) tkhd->duration, buffer, size, offset);
1720   } else {
1721     prop_copy_uint64 (tkhd->creation_time, buffer, size, offset);
1722     prop_copy_uint64 (tkhd->modification_time, buffer, size, offset);
1723     prop_copy_uint32 (tkhd->track_ID, buffer, size, offset);
1724     prop_copy_uint32 (tkhd->reserved, buffer, size, offset);
1725     prop_copy_uint64 (tkhd->duration, buffer, size, offset);
1726   }
1727
1728   prop_copy_uint32_array (tkhd->reserved2, 2, buffer, size, offset);
1729   prop_copy_uint16 (tkhd->layer, buffer, size, offset);
1730   prop_copy_uint16 (tkhd->alternate_group, buffer, size, offset);
1731   prop_copy_uint16 (tkhd->volume, buffer, size, offset);
1732   prop_copy_uint16 (tkhd->reserved3, buffer, size, offset);
1733   prop_copy_uint32_array (tkhd->matrix, 9, buffer, size, offset);
1734
1735   prop_copy_uint32 (tkhd->width, buffer, size, offset);
1736   prop_copy_uint32 (tkhd->height, buffer, size, offset);
1737
1738   atom_write_size (buffer, size, offset, original_offset);
1739   return *offset - original_offset;
1740 }
1741
1742 static guint64
1743 atom_hdlr_copy_data (AtomHDLR * hdlr, guint8 ** buffer, guint64 * size,
1744     guint64 * offset)
1745 {
1746   guint64 original_offset = *offset;
1747
1748   if (!atom_full_copy_data (&hdlr->header, buffer, size, offset)) {
1749     return 0;
1750   }
1751
1752   prop_copy_fourcc (hdlr->component_type, buffer, size, offset);
1753   prop_copy_fourcc (hdlr->handler_type, buffer, size, offset);
1754   prop_copy_fourcc (hdlr->manufacturer, buffer, size, offset);
1755   prop_copy_uint32 (hdlr->flags, buffer, size, offset);
1756   prop_copy_uint32 (hdlr->flags_mask, buffer, size, offset);
1757
1758   if (hdlr->flavor == ATOMS_TREE_FLAVOR_MOV) {
1759     prop_copy_size_string ((guint8 *) hdlr->name, strlen (hdlr->name), buffer,
1760         size, offset);
1761   } else {
1762     /* assume isomedia base is more generic and use null terminated */
1763     prop_copy_null_terminated_string (hdlr->name, buffer, size, offset);
1764   }
1765
1766   atom_write_size (buffer, size, offset, original_offset);
1767   return *offset - original_offset;
1768 }
1769
1770 static guint64
1771 atom_vmhd_copy_data (AtomVMHD * vmhd, guint8 ** buffer, guint64 * size,
1772     guint64 * offset)
1773 {
1774   guint64 original_offset = *offset;
1775
1776   if (!atom_full_copy_data (&vmhd->header, buffer, size, offset)) {
1777     return 0;
1778   }
1779   prop_copy_uint16 (vmhd->graphics_mode, buffer, size, offset);
1780   prop_copy_uint16_array (vmhd->opcolor, 3, buffer, size, offset);
1781
1782   atom_write_size (buffer, size, offset, original_offset);
1783   return original_offset - *offset;
1784 }
1785
1786 static guint64
1787 atom_smhd_copy_data (AtomSMHD * smhd, guint8 ** buffer, guint64 * size,
1788     guint64 * offset)
1789 {
1790   guint64 original_offset = *offset;
1791
1792   if (!atom_full_copy_data (&smhd->header, buffer, size, offset)) {
1793     return 0;
1794   }
1795   prop_copy_uint16 (smhd->balance, buffer, size, offset);
1796   prop_copy_uint16 (smhd->reserved, buffer, size, offset);
1797
1798   atom_write_size (buffer, size, offset, original_offset);
1799   return original_offset - *offset;
1800 }
1801
1802 static guint64
1803 atom_hmhd_copy_data (AtomHMHD * hmhd, guint8 ** buffer, guint64 * size,
1804     guint64 * offset)
1805 {
1806   guint64 original_offset = *offset;
1807
1808   if (!atom_full_copy_data (&hmhd->header, buffer, size, offset)) {
1809     return 0;
1810   }
1811   prop_copy_uint16 (hmhd->max_pdu_size, buffer, size, offset);
1812   prop_copy_uint16 (hmhd->avg_pdu_size, buffer, size, offset);
1813   prop_copy_uint32 (hmhd->max_bitrate, buffer, size, offset);
1814   prop_copy_uint32 (hmhd->avg_bitrate, buffer, size, offset);
1815   prop_copy_uint32 (hmhd->sliding_avg_bitrate, buffer, size, offset);
1816
1817   atom_write_size (buffer, size, offset, original_offset);
1818   return original_offset - *offset;
1819 }
1820
1821 static guint64
1822 atom_tcmi_copy_data (AtomTCMI * tcmi, guint8 ** buffer, guint64 * size,
1823     guint64 * offset)
1824 {
1825   guint64 original_offset = *offset;
1826
1827   if (!atom_full_copy_data (&tcmi->header, buffer, size, offset)) {
1828     return 0;
1829   }
1830   prop_copy_uint16 (tcmi->text_font, buffer, size, offset);
1831   prop_copy_uint16 (tcmi->text_face, buffer, size, offset);
1832   prop_copy_uint16 (tcmi->text_size, buffer, size, offset);
1833   prop_copy_uint16 (tcmi->text_color[0], buffer, size, offset);
1834   prop_copy_uint16 (tcmi->text_color[1], buffer, size, offset);
1835   prop_copy_uint16 (tcmi->text_color[2], buffer, size, offset);
1836   prop_copy_uint16 (tcmi->bg_color[0], buffer, size, offset);
1837   prop_copy_uint16 (tcmi->bg_color[1], buffer, size, offset);
1838   prop_copy_uint16 (tcmi->bg_color[2], buffer, size, offset);
1839   /* reserved */
1840   prop_copy_uint16 (0, buffer, size, offset);
1841   prop_copy_size_string ((guint8 *) tcmi->font_name, strlen (tcmi->font_name),
1842       buffer, size, offset);
1843
1844   atom_write_size (buffer, size, offset, original_offset);
1845   return original_offset - *offset;
1846 }
1847
1848 static guint64
1849 atom_tmcd_copy_data (AtomTMCD * tmcd, guint8 ** buffer, guint64 * size,
1850     guint64 * offset)
1851 {
1852   guint64 original_offset = *offset;
1853
1854   if (!atom_copy_data (&tmcd->header, buffer, size, offset)) {
1855     return 0;
1856   }
1857   if (!atom_tcmi_copy_data (&tmcd->tcmi, buffer, size, offset)) {
1858     return 0;
1859   }
1860
1861   atom_write_size (buffer, size, offset, original_offset);
1862   return original_offset - *offset;
1863 }
1864
1865 static guint64
1866 atom_gmin_copy_data (AtomGMIN * gmin, guint8 ** buffer, guint64 * size,
1867     guint64 * offset)
1868 {
1869   guint64 original_offset = *offset;
1870
1871   if (!atom_full_copy_data (&gmin->header, buffer, size, offset)) {
1872     return 0;
1873   }
1874   prop_copy_uint16 (gmin->graphics_mode, buffer, size, offset);
1875   prop_copy_uint16 (gmin->opcolor[0], buffer, size, offset);
1876   prop_copy_uint16 (gmin->opcolor[1], buffer, size, offset);
1877   prop_copy_uint16 (gmin->opcolor[2], buffer, size, offset);
1878   prop_copy_uint8 (gmin->balance, buffer, size, offset);
1879   /* reserved */
1880   prop_copy_uint8 (0, buffer, size, offset);
1881
1882   atom_write_size (buffer, size, offset, original_offset);
1883   return original_offset - *offset;
1884 }
1885
1886 static guint64
1887 atom_gmhd_copy_data (AtomGMHD * gmhd, guint8 ** buffer, guint64 * size,
1888     guint64 * offset)
1889 {
1890   guint64 original_offset = *offset;
1891
1892   if (!atom_copy_data (&gmhd->header, buffer, size, offset)) {
1893     return 0;
1894   }
1895   if (!atom_gmin_copy_data (&gmhd->gmin, buffer, size, offset)) {
1896     return 0;
1897   }
1898   if (!atom_tmcd_copy_data (&gmhd->tmcd, buffer, size, offset)) {
1899     return 0;
1900   }
1901
1902   atom_write_size (buffer, size, offset, original_offset);
1903   return original_offset - *offset;
1904 }
1905
1906 static gboolean
1907 atom_url_same_file_flag (AtomURL * url)
1908 {
1909   return (url->header.flags[2] & 0x1) == 1;
1910 }
1911
1912 static guint64
1913 atom_url_copy_data (AtomURL * url, guint8 ** buffer, guint64 * size,
1914     guint64 * offset)
1915 {
1916   guint64 original_offset = *offset;
1917
1918   if (!atom_full_copy_data (&url->header, buffer, size, offset)) {
1919     return 0;
1920   }
1921
1922   if (!atom_url_same_file_flag (url)) {
1923     prop_copy_null_terminated_string (url->location, buffer, size, offset);
1924   }
1925
1926   atom_write_size (buffer, size, offset, original_offset);
1927   return original_offset - *offset;
1928 }
1929
1930 guint64
1931 atom_stts_copy_data (AtomSTTS * stts, guint8 ** buffer, guint64 * size,
1932     guint64 * offset)
1933 {
1934   guint64 original_offset = *offset;
1935   guint i;
1936
1937   if (!atom_full_copy_data (&stts->header, buffer, size, offset)) {
1938     return 0;
1939   }
1940
1941   prop_copy_uint32 (atom_array_get_len (&stts->entries), buffer, size, offset);
1942   /* minimize realloc */
1943   prop_copy_ensure_buffer (buffer, size, offset,
1944       8 * atom_array_get_len (&stts->entries));
1945   for (i = 0; i < atom_array_get_len (&stts->entries); i++) {
1946     STTSEntry *entry = &atom_array_index (&stts->entries, i);
1947
1948     prop_copy_uint32 (entry->sample_count, buffer, size, offset);
1949     prop_copy_int32 (entry->sample_delta, buffer, size, offset);
1950   }
1951
1952   atom_write_size (buffer, size, offset, original_offset);
1953   return *offset - original_offset;
1954 }
1955
1956 static guint64
1957 atom_sample_entry_copy_data (SampleTableEntry * se, guint8 ** buffer,
1958     guint64 * size, guint64 * offset)
1959 {
1960   guint64 original_offset = *offset;
1961
1962   if (!atom_copy_data (&se->header, buffer, size, offset)) {
1963     return 0;
1964   }
1965
1966   prop_copy_uint8_array (se->reserved, 6, buffer, size, offset);
1967   prop_copy_uint16 (se->data_reference_index, buffer, size, offset);
1968
1969   return *offset - original_offset;
1970 }
1971
1972 static guint64
1973 atom_esds_copy_data (AtomESDS * esds, guint8 ** buffer, guint64 * size,
1974     guint64 * offset)
1975 {
1976   guint64 original_offset = *offset;
1977
1978   if (!atom_full_copy_data (&esds->header, buffer, size, offset)) {
1979     return 0;
1980   }
1981   if (!desc_es_descriptor_copy_data (&esds->es, buffer, size, offset)) {
1982     return 0;
1983   }
1984
1985   atom_write_size (buffer, size, offset, original_offset);
1986   return *offset - original_offset;
1987 }
1988
1989 static guint64
1990 atom_frma_copy_data (AtomFRMA * frma, guint8 ** buffer,
1991     guint64 * size, guint64 * offset)
1992 {
1993   guint64 original_offset = *offset;
1994
1995   if (!atom_copy_data (&(frma->header), buffer, size, offset))
1996     return 0;
1997
1998   prop_copy_fourcc (frma->media_type, buffer, size, offset);
1999
2000   atom_write_size (buffer, size, offset, original_offset);
2001   return *offset - original_offset;
2002 }
2003
2004 static guint64
2005 atom_hint_sample_entry_copy_data (AtomHintSampleEntry * hse, guint8 ** buffer,
2006     guint64 * size, guint64 * offset)
2007 {
2008   guint64 original_offset = *offset;
2009
2010   if (!atom_sample_entry_copy_data (&hse->se, buffer, size, offset)) {
2011     return 0;
2012   }
2013
2014   prop_copy_uint32 (hse->size, buffer, size, offset);
2015   prop_copy_uint8_array (hse->data, hse->size, buffer, size, offset);
2016
2017   atom_write_size (buffer, size, offset, original_offset);
2018   return *offset - original_offset;
2019 }
2020
2021 static guint64
2022 sample_entry_mp4a_copy_data (SampleTableEntryMP4A * mp4a, guint8 ** buffer,
2023     guint64 * size, guint64 * offset)
2024 {
2025   guint64 original_offset = *offset;
2026
2027   if (!atom_sample_entry_copy_data (&mp4a->se, buffer, size, offset)) {
2028     return 0;
2029   }
2030
2031   prop_copy_uint16 (mp4a->version, buffer, size, offset);
2032   prop_copy_uint16 (mp4a->revision_level, buffer, size, offset);
2033   prop_copy_uint32 (mp4a->vendor, buffer, size, offset);
2034   prop_copy_uint16 (mp4a->channels, buffer, size, offset);
2035   prop_copy_uint16 (mp4a->sample_size, buffer, size, offset);
2036   prop_copy_uint16 (mp4a->compression_id, buffer, size, offset);
2037   prop_copy_uint16 (mp4a->packet_size, buffer, size, offset);
2038   prop_copy_uint32 (mp4a->sample_rate, buffer, size, offset);
2039
2040   /* this should always be 0 for mp4 flavor */
2041   if (mp4a->version == 1) {
2042     prop_copy_uint32 (mp4a->samples_per_packet, buffer, size, offset);
2043     prop_copy_uint32 (mp4a->bytes_per_packet, buffer, size, offset);
2044     prop_copy_uint32 (mp4a->bytes_per_frame, buffer, size, offset);
2045     prop_copy_uint32 (mp4a->bytes_per_sample, buffer, size, offset);
2046   }
2047
2048   if (mp4a->extension_atoms) {
2049     if (!atom_info_list_copy_data (mp4a->extension_atoms, buffer, size, offset))
2050       return 0;
2051   }
2052
2053   atom_write_size (buffer, size, offset, original_offset);
2054   return *offset - original_offset;
2055 }
2056
2057 static guint64
2058 sample_entry_mp4v_copy_data (SampleTableEntryMP4V * mp4v, guint8 ** buffer,
2059     guint64 * size, guint64 * offset)
2060 {
2061   guint64 original_offset = *offset;
2062
2063   if (!atom_sample_entry_copy_data (&mp4v->se, buffer, size, offset)) {
2064     return 0;
2065   }
2066
2067   prop_copy_uint16 (mp4v->version, buffer, size, offset);
2068   prop_copy_uint16 (mp4v->revision_level, buffer, size, offset);
2069   prop_copy_fourcc (mp4v->vendor, buffer, size, offset);
2070   prop_copy_uint32 (mp4v->temporal_quality, buffer, size, offset);
2071   prop_copy_uint32 (mp4v->spatial_quality, buffer, size, offset);
2072
2073   prop_copy_uint16 (mp4v->width, buffer, size, offset);
2074   prop_copy_uint16 (mp4v->height, buffer, size, offset);
2075
2076   prop_copy_uint32 (mp4v->horizontal_resolution, buffer, size, offset);
2077   prop_copy_uint32 (mp4v->vertical_resolution, buffer, size, offset);
2078   prop_copy_uint32 (mp4v->datasize, buffer, size, offset);
2079
2080   prop_copy_uint16 (mp4v->frame_count, buffer, size, offset);
2081
2082   prop_copy_fixed_size_string ((guint8 *) mp4v->compressor, 32, buffer, size,
2083       offset);
2084
2085   prop_copy_uint16 (mp4v->depth, buffer, size, offset);
2086   prop_copy_uint16 (mp4v->color_table_id, buffer, size, offset);
2087
2088   /* extra atoms */
2089   if (mp4v->extension_atoms &&
2090       !atom_info_list_copy_data (mp4v->extension_atoms, buffer, size, offset))
2091     return 0;
2092
2093   atom_write_size (buffer, size, offset, original_offset);
2094   return *offset - original_offset;
2095 }
2096
2097 static guint64
2098 sample_entry_tx3g_copy_data (SampleTableEntryTX3G * tx3g, guint8 ** buffer,
2099     guint64 * size, guint64 * offset)
2100 {
2101   guint64 original_offset = *offset;
2102
2103   if (!atom_sample_entry_copy_data (&tx3g->se, buffer, size, offset)) {
2104     return 0;
2105   }
2106
2107   prop_copy_uint32 (tx3g->display_flags, buffer, size, offset);
2108
2109   /* reserved */
2110   prop_copy_uint8 (1, buffer, size, offset);
2111   prop_copy_uint8 (-1, buffer, size, offset);
2112   prop_copy_uint32 (0, buffer, size, offset);
2113
2114   prop_copy_uint64 (tx3g->default_text_box, buffer, size, offset);
2115
2116   /* reserved */
2117   prop_copy_uint32 (0, buffer, size, offset);
2118
2119   prop_copy_uint16 (tx3g->font_id, buffer, size, offset);
2120   prop_copy_uint8 (tx3g->font_face, buffer, size, offset);
2121   prop_copy_uint8 (tx3g->font_size, buffer, size, offset);
2122   prop_copy_uint32 (tx3g->foreground_color_rgba, buffer, size, offset);
2123
2124   /* it must have a fonttable atom */
2125   {
2126     Atom atom;
2127
2128     atom_header_set (&atom, FOURCC_ftab, 18, 0);
2129     if (!atom_copy_data (&atom, buffer, size, offset))
2130       return 0;
2131     prop_copy_uint16 (1, buffer, size, offset); /* Count must be 1 */
2132     prop_copy_uint16 (1, buffer, size, offset); /* Font id: 1 */
2133     prop_copy_size_string ((guint8 *) "Serif", 5, buffer, size, offset);
2134   }
2135
2136   atom_write_size (buffer, size, offset, original_offset);
2137   return *offset - original_offset;
2138 }
2139
2140 static guint64
2141 sample_entry_tmcd_copy_data (SampleTableEntryTMCD * tmcd, guint8 ** buffer,
2142     guint64 * size, guint64 * offset)
2143 {
2144   guint64 original_offset = *offset;
2145
2146   if (!atom_sample_entry_copy_data (&tmcd->se, buffer, size, offset)) {
2147     return 0;
2148   }
2149
2150   /* reserved */
2151   prop_copy_uint32 (0, buffer, size, offset);
2152
2153   prop_copy_uint32 (tmcd->tc_flags, buffer, size, offset);
2154   prop_copy_uint32 (tmcd->timescale, buffer, size, offset);
2155   prop_copy_uint32 (tmcd->frame_duration, buffer, size, offset);
2156   prop_copy_uint8 (tmcd->n_frames, buffer, size, offset);
2157
2158   /* reserved */
2159   prop_copy_uint8 (0, buffer, size, offset);
2160   {
2161     Atom atom;
2162     guint64 name_offset = *offset;
2163
2164     atom_header_set (&atom, FOURCC_name, 0, 0);
2165     if (!atom_copy_data (&atom, buffer, size, offset))
2166       return 0;
2167     prop_copy_uint16 (strlen (tmcd->name.name), buffer, size, offset);
2168     prop_copy_uint16 (tmcd->name.language_code, buffer, size, offset);
2169     prop_copy_fixed_size_string ((guint8 *) tmcd->name.name,
2170         strlen (tmcd->name.name), buffer, size, offset);
2171
2172     atom_write_size (buffer, size, offset, name_offset);
2173   }
2174
2175   atom_write_size (buffer, size, offset, original_offset);
2176   return *offset - original_offset;
2177 }
2178
2179 guint64
2180 atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
2181     guint64 * offset)
2182 {
2183   guint64 original_offset = *offset;
2184   guint i;
2185
2186   if (!atom_full_copy_data (&stsz->header, buffer, size, offset)) {
2187     return 0;
2188   }
2189
2190   prop_copy_uint32 (stsz->sample_size, buffer, size, offset);
2191   prop_copy_uint32 (stsz->table_size, buffer, size, offset);
2192   if (stsz->sample_size == 0) {
2193     /* minimize realloc */
2194     prop_copy_ensure_buffer (buffer, size, offset, 4 * stsz->table_size);
2195     /* entry count must match sample count */
2196     g_assert (atom_array_get_len (&stsz->entries) == stsz->table_size);
2197     for (i = 0; i < atom_array_get_len (&stsz->entries); i++) {
2198       prop_copy_uint32 (atom_array_index (&stsz->entries, i), buffer, size,
2199           offset);
2200     }
2201   }
2202
2203   atom_write_size (buffer, size, offset, original_offset);
2204   return *offset - original_offset;
2205 }
2206
2207 guint64
2208 atom_stsc_copy_data (AtomSTSC * stsc, guint8 ** buffer, guint64 * size,
2209     guint64 * offset)
2210 {
2211   guint64 original_offset = *offset;
2212   guint i, len;
2213
2214   if (!atom_full_copy_data (&stsc->header, buffer, size, offset)) {
2215     return 0;
2216   }
2217
2218   /* Last two entries might be the same size here as we only merge once the
2219    * next chunk is started */
2220   if ((len = atom_array_get_len (&stsc->entries)) > 1 &&
2221       ((atom_array_index (&stsc->entries, len - 1)).samples_per_chunk ==
2222           (atom_array_index (&stsc->entries, len - 2)).samples_per_chunk)) {
2223     stsc->entries.len--;
2224   }
2225
2226   prop_copy_uint32 (atom_array_get_len (&stsc->entries), buffer, size, offset);
2227   /* minimize realloc */
2228   prop_copy_ensure_buffer (buffer, size, offset,
2229       12 * atom_array_get_len (&stsc->entries));
2230
2231   for (i = 0; i < atom_array_get_len (&stsc->entries); i++) {
2232     STSCEntry *entry = &atom_array_index (&stsc->entries, i);
2233
2234     prop_copy_uint32 (entry->first_chunk, buffer, size, offset);
2235     prop_copy_uint32 (entry->samples_per_chunk, buffer, size, offset);
2236     prop_copy_uint32 (entry->sample_description_index, buffer, size, offset);
2237   }
2238
2239   atom_write_size (buffer, size, offset, original_offset);
2240   return *offset - original_offset;
2241 }
2242
2243 guint64
2244 atom_ctts_copy_data (AtomCTTS * ctts, guint8 ** buffer, guint64 * size,
2245     guint64 * offset)
2246 {
2247   guint64 original_offset = *offset;
2248   guint i;
2249
2250   if (!atom_full_copy_data (&ctts->header, buffer, size, offset)) {
2251     return 0;
2252   }
2253
2254   prop_copy_uint32 (atom_array_get_len (&ctts->entries), buffer, size, offset);
2255   /* minimize realloc */
2256   prop_copy_ensure_buffer (buffer, size, offset,
2257       8 * atom_array_get_len (&ctts->entries));
2258   for (i = 0; i < atom_array_get_len (&ctts->entries); i++) {
2259     CTTSEntry *entry = &atom_array_index (&ctts->entries, i);
2260
2261     prop_copy_uint32 (entry->samplecount, buffer, size, offset);
2262     prop_copy_uint32 (entry->sampleoffset, buffer, size, offset);
2263   }
2264
2265   atom_write_size (buffer, size, offset, original_offset);
2266   return *offset - original_offset;
2267 }
2268
2269 guint64
2270 atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size,
2271     guint64 * offset)
2272 {
2273   guint64 original_offset = *offset;
2274   guint i;
2275   gboolean trunc_to_32 = stco64->header.header.type == FOURCC_stco;
2276
2277   if (!atom_full_copy_data (&stco64->header, buffer, size, offset)) {
2278     return 0;
2279   }
2280
2281   prop_copy_uint32 (atom_array_get_len (&stco64->entries), buffer, size,
2282       offset);
2283
2284   /* minimize realloc */
2285   prop_copy_ensure_buffer (buffer, size, offset,
2286       8 * atom_array_get_len (&stco64->entries));
2287   for (i = 0; i < atom_array_get_len (&stco64->entries); i++) {
2288     guint64 value =
2289         atom_array_index (&stco64->entries, i) + stco64->chunk_offset;
2290
2291     if (trunc_to_32) {
2292       prop_copy_uint32 ((guint32) value, buffer, size, offset);
2293     } else {
2294       prop_copy_uint64 (value, buffer, size, offset);
2295     }
2296   }
2297
2298   atom_write_size (buffer, size, offset, original_offset);
2299   return *offset - original_offset;
2300 }
2301
2302 guint64
2303 atom_stss_copy_data (AtomSTSS * stss, guint8 ** buffer, guint64 * size,
2304     guint64 * offset)
2305 {
2306   guint64 original_offset = *offset;
2307   guint i;
2308
2309   if (atom_array_get_len (&stss->entries) == 0) {
2310     /* FIXME not needing this atom might be confused with error while copying */
2311     return 0;
2312   }
2313
2314   if (!atom_full_copy_data (&stss->header, buffer, size, offset)) {
2315     return 0;
2316   }
2317
2318   prop_copy_uint32 (atom_array_get_len (&stss->entries), buffer, size, offset);
2319   /* minimize realloc */
2320   prop_copy_ensure_buffer (buffer, size, offset,
2321       4 * atom_array_get_len (&stss->entries));
2322   for (i = 0; i < atom_array_get_len (&stss->entries); i++) {
2323     prop_copy_uint32 (atom_array_index (&stss->entries, i), buffer, size,
2324         offset);
2325   }
2326
2327   atom_write_size (buffer, size, offset, original_offset);
2328   return *offset - original_offset;
2329 }
2330
2331 static guint64
2332 atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size,
2333     guint64 * offset)
2334 {
2335   guint64 original_offset = *offset;
2336   GList *walker;
2337
2338   if (!atom_full_copy_data (&stsd->header, buffer, size, offset)) {
2339     return 0;
2340   }
2341
2342   prop_copy_uint32 (stsd->n_entries, buffer, size, offset);
2343
2344   for (walker = g_list_last (stsd->entries); walker != NULL;
2345       walker = g_list_previous (walker)) {
2346     SampleTableEntry *se = (SampleTableEntry *) walker->data;
2347
2348     switch (((Atom *) walker->data)->type) {
2349       case FOURCC_mp4a:
2350         if (!sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) walker->data,
2351                 buffer, size, offset)) {
2352           return 0;
2353         }
2354         break;
2355       case FOURCC_mp4v:
2356         if (!sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) walker->data,
2357                 buffer, size, offset)) {
2358           return 0;
2359         }
2360         break;
2361       default:
2362         if (se->kind == VIDEO) {
2363           if (!sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *)
2364                   walker->data, buffer, size, offset)) {
2365             return 0;
2366           }
2367         } else if (se->kind == AUDIO) {
2368           if (!sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *)
2369                   walker->data, buffer, size, offset)) {
2370             return 0;
2371           }
2372         } else if (se->kind == SUBTITLE) {
2373           if (!sample_entry_tx3g_copy_data ((SampleTableEntryTX3G *)
2374                   walker->data, buffer, size, offset)) {
2375             return 0;
2376           }
2377         } else if (se->kind == TIMECODE) {
2378           if (!sample_entry_tmcd_copy_data ((SampleTableEntryTMCD *)
2379                   walker->data, buffer, size, offset)) {
2380             return 0;
2381           }
2382         } else {
2383           if (!atom_hint_sample_entry_copy_data (
2384                   (AtomHintSampleEntry *) walker->data, buffer, size, offset)) {
2385             return 0;
2386           }
2387         }
2388         break;
2389     }
2390   }
2391
2392   atom_write_size (buffer, size, offset, original_offset);
2393   return *offset - original_offset;
2394 }
2395
2396 static guint64
2397 atom_stbl_copy_data (AtomSTBL * stbl, guint8 ** buffer, guint64 * size,
2398     guint64 * offset)
2399 {
2400   guint64 original_offset = *offset;
2401
2402   if (!atom_copy_data (&stbl->header, buffer, size, offset)) {
2403     return 0;
2404   }
2405
2406   if (!atom_stsd_copy_data (&stbl->stsd, buffer, size, offset)) {
2407     return 0;
2408   }
2409   if (!atom_stts_copy_data (&stbl->stts, buffer, size, offset)) {
2410     return 0;
2411   }
2412   /* this atom is optional, so let's check if we need it
2413    * (to avoid false error) */
2414   if (atom_array_get_len (&stbl->stss.entries)) {
2415     if (!atom_stss_copy_data (&stbl->stss, buffer, size, offset)) {
2416       return 0;
2417     }
2418   }
2419
2420   if (!atom_stsc_copy_data (&stbl->stsc, buffer, size, offset)) {
2421     return 0;
2422   }
2423   if (!atom_stsz_copy_data (&stbl->stsz, buffer, size, offset)) {
2424     return 0;
2425   }
2426   if (stbl->ctts && stbl->ctts->do_pts) {
2427     if (!atom_ctts_copy_data (stbl->ctts, buffer, size, offset)) {
2428       return 0;
2429     }
2430   }
2431   if (!atom_stco64_copy_data (&stbl->stco64, buffer, size, offset)) {
2432     return 0;
2433   }
2434
2435   atom_write_size (buffer, size, offset, original_offset);
2436   return original_offset - *offset;
2437 }
2438
2439
2440 static guint64
2441 atom_dref_copy_data (AtomDREF * dref, guint8 ** buffer, guint64 * size,
2442     guint64 * offset)
2443 {
2444   guint64 original_offset = *offset;
2445   GList *walker;
2446
2447   if (!atom_full_copy_data (&dref->header, buffer, size, offset)) {
2448     return 0;
2449   }
2450
2451   prop_copy_uint32 (g_list_length (dref->entries), buffer, size, offset);
2452
2453   walker = dref->entries;
2454   while (walker != NULL) {
2455     Atom *atom = (Atom *) walker->data;
2456
2457     if (atom->type == FOURCC_url_) {
2458       if (!atom_url_copy_data ((AtomURL *) atom, buffer, size, offset))
2459         return 0;
2460     } else if (atom->type == FOURCC_alis) {
2461       if (!atom_full_copy_data ((AtomFull *) atom, buffer, size, offset))
2462         return 0;
2463     } else {
2464       g_error ("Unsupported atom used inside dref atom");
2465     }
2466     walker = g_list_next (walker);
2467   }
2468
2469   atom_write_size (buffer, size, offset, original_offset);
2470   return *offset - original_offset;
2471 }
2472
2473 static guint64
2474 atom_dinf_copy_data (AtomDINF * dinf, guint8 ** buffer, guint64 * size,
2475     guint64 * offset)
2476 {
2477   guint64 original_offset = *offset;
2478
2479   if (!atom_copy_data (&dinf->header, buffer, size, offset)) {
2480     return 0;
2481   }
2482
2483   if (!atom_dref_copy_data (&dinf->dref, buffer, size, offset)) {
2484     return 0;
2485   }
2486
2487   atom_write_size (buffer, size, offset, original_offset);
2488   return original_offset - *offset;
2489 }
2490
2491 static guint64
2492 atom_minf_copy_data (AtomMINF * minf, guint8 ** buffer, guint64 * size,
2493     guint64 * offset)
2494 {
2495   guint64 original_offset = *offset;
2496
2497   if (!atom_copy_data (&minf->header, buffer, size, offset)) {
2498     return 0;
2499   }
2500
2501   if (minf->vmhd) {
2502     if (!atom_vmhd_copy_data (minf->vmhd, buffer, size, offset)) {
2503       return 0;
2504     }
2505   } else if (minf->smhd) {
2506     if (!atom_smhd_copy_data (minf->smhd, buffer, size, offset)) {
2507       return 0;
2508     }
2509   } else if (minf->hmhd) {
2510     if (!atom_hmhd_copy_data (minf->hmhd, buffer, size, offset)) {
2511       return 0;
2512     }
2513   } else if (minf->gmhd) {
2514     if (!atom_gmhd_copy_data (minf->gmhd, buffer, size, offset)) {
2515       return 0;
2516     }
2517   }
2518
2519   if (minf->hdlr) {
2520     if (!atom_hdlr_copy_data (minf->hdlr, buffer, size, offset)) {
2521       return 0;
2522     }
2523   }
2524
2525   if (!atom_dinf_copy_data (&minf->dinf, buffer, size, offset)) {
2526     return 0;
2527   }
2528   if (!atom_stbl_copy_data (&minf->stbl, buffer, size, offset)) {
2529     return 0;
2530   }
2531
2532   atom_write_size (buffer, size, offset, original_offset);
2533   return *offset - original_offset;
2534 }
2535
2536 static guint64
2537 atom_mdhd_copy_data (AtomMDHD * mdhd, guint8 ** buffer, guint64 * size,
2538     guint64 * offset)
2539 {
2540   guint64 original_offset = *offset;
2541
2542   if (!atom_full_copy_data (&mdhd->header, buffer, size, offset)) {
2543     return 0;
2544   }
2545
2546   if (!common_time_info_copy_data (&mdhd->time_info,
2547           atom_full_get_version (&mdhd->header) == 0, buffer, size, offset)) {
2548     return 0;
2549   }
2550
2551   prop_copy_uint16 (mdhd->language_code, buffer, size, offset);
2552   prop_copy_uint16 (mdhd->quality, buffer, size, offset);
2553
2554   atom_write_size (buffer, size, offset, original_offset);
2555   return *offset - original_offset;
2556 }
2557
2558 static guint64
2559 atom_mdia_copy_data (AtomMDIA * mdia, guint8 ** buffer, guint64 * size,
2560     guint64 * offset)
2561 {
2562   guint64 original_offset = *offset;
2563
2564   if (!atom_copy_data (&mdia->header, buffer, size, offset)) {
2565     return 0;
2566   }
2567   if (!atom_mdhd_copy_data (&mdia->mdhd, buffer, size, offset)) {
2568     return 0;
2569   }
2570   if (!atom_hdlr_copy_data (&mdia->hdlr, buffer, size, offset)) {
2571     return 0;
2572   }
2573
2574   if (!atom_minf_copy_data (&mdia->minf, buffer, size, offset)) {
2575     return 0;
2576   }
2577
2578   atom_write_size (buffer, size, offset, original_offset);
2579   return *offset - original_offset;
2580 }
2581
2582 static guint64
2583 atom_elst_copy_data (AtomELST * elst, guint8 ** buffer, guint64 * size,
2584     guint64 * offset)
2585 {
2586   guint64 original_offset = *offset;
2587   GSList *walker;
2588
2589   if (!atom_full_copy_data (&elst->header, buffer, size, offset)) {
2590     return 0;
2591   }
2592
2593   prop_copy_uint32 (g_slist_length (elst->entries), buffer, size, offset);
2594
2595   for (walker = elst->entries; walker != NULL; walker = g_slist_next (walker)) {
2596     EditListEntry *entry = (EditListEntry *) walker->data;
2597     prop_copy_uint32 (entry->duration, buffer, size, offset);
2598     prop_copy_uint32 (entry->media_time, buffer, size, offset);
2599     prop_copy_uint32 (entry->media_rate, buffer, size, offset);
2600   }
2601   atom_write_size (buffer, size, offset, original_offset);
2602   return *offset - original_offset;
2603 }
2604
2605 static guint64
2606 atom_tref_copy_data (AtomTREF * tref, guint8 ** buffer, guint64 * size,
2607     guint64 * offset)
2608 {
2609   guint64 original_offset = *offset;
2610   guint i;
2611
2612   g_assert (atom_array_get_len (&tref->entries) > 0);
2613
2614   if (!atom_copy_data (&tref->header, buffer, size, offset)) {
2615     return 0;
2616   }
2617
2618   prop_copy_uint32 (8 + 4 * atom_array_get_len (&tref->entries), buffer, size,
2619       offset);
2620   prop_copy_fourcc (tref->reftype, buffer, size, offset);
2621   /* minimize realloc */
2622   prop_copy_ensure_buffer (buffer, size, offset,
2623       4 * atom_array_get_len (&tref->entries));
2624   for (i = 0; i < atom_array_get_len (&tref->entries); i++) {
2625     prop_copy_uint32 (atom_array_index (&tref->entries, i), buffer, size,
2626         offset);
2627   }
2628
2629   atom_write_size (buffer, size, offset, original_offset);
2630   return *offset - original_offset;
2631 }
2632
2633 static guint64
2634 atom_edts_copy_data (AtomEDTS * edts, guint8 ** buffer, guint64 * size,
2635     guint64 * offset)
2636 {
2637   guint64 original_offset = *offset;
2638
2639   if (!atom_copy_data (&(edts->header), buffer, size, offset))
2640     return 0;
2641
2642   if (!atom_elst_copy_data (&(edts->elst), buffer, size, offset))
2643     return 0;
2644
2645   atom_write_size (buffer, size, offset, original_offset);
2646   return *offset - original_offset;
2647 }
2648
2649 static guint64
2650 atom_tag_data_copy_data (AtomTagData * data, guint8 ** buffer, guint64 * size,
2651     guint64 * offset)
2652 {
2653   guint64 original_offset = *offset;
2654
2655   if (!atom_full_copy_data (&data->header, buffer, size, offset)) {
2656     return 0;
2657   }
2658
2659   prop_copy_uint32 (data->reserved, buffer, size, offset);
2660   prop_copy_uint8_array (data->data, data->datalen, buffer, size, offset);
2661
2662   atom_write_size (buffer, size, offset, original_offset);
2663   return *offset - original_offset;
2664 }
2665
2666 static guint64
2667 atom_tag_copy_data (AtomTag * tag, guint8 ** buffer, guint64 * size,
2668     guint64 * offset)
2669 {
2670   guint64 original_offset = *offset;
2671
2672   if (!atom_copy_data (&tag->header, buffer, size, offset)) {
2673     return 0;
2674   }
2675
2676   if (!atom_tag_data_copy_data (&tag->data, buffer, size, offset)) {
2677     return 0;
2678   }
2679
2680   atom_write_size (buffer, size, offset, original_offset);
2681   return *offset - original_offset;
2682 }
2683
2684 static guint64
2685 atom_ilst_copy_data (AtomILST * ilst, guint8 ** buffer, guint64 * size,
2686     guint64 * offset)
2687 {
2688   guint64 original_offset = *offset;
2689
2690   if (!atom_copy_data (&ilst->header, buffer, size, offset)) {
2691     return 0;
2692   }
2693   /* extra atoms */
2694   if (ilst->entries &&
2695       !atom_info_list_copy_data (ilst->entries, buffer, size, offset))
2696     return 0;
2697
2698   atom_write_size (buffer, size, offset, original_offset);
2699   return *offset - original_offset;
2700 }
2701
2702 static guint64
2703 atom_meta_copy_data (AtomMETA * meta, guint8 ** buffer, guint64 * size,
2704     guint64 * offset)
2705 {
2706   guint64 original_offset = *offset;
2707
2708   if (!atom_full_copy_data (&meta->header, buffer, size, offset)) {
2709     return 0;
2710   }
2711   if (!atom_hdlr_copy_data (&meta->hdlr, buffer, size, offset)) {
2712     return 0;
2713   }
2714   if (meta->ilst) {
2715     if (!atom_ilst_copy_data (meta->ilst, buffer, size, offset)) {
2716       return 0;
2717     }
2718   }
2719
2720   atom_write_size (buffer, size, offset, original_offset);
2721   return *offset - original_offset;
2722 }
2723
2724 static guint64
2725 atom_udta_copy_data (AtomUDTA * udta, guint8 ** buffer, guint64 * size,
2726     guint64 * offset)
2727 {
2728   guint64 original_offset = *offset;
2729
2730   if (!atom_copy_data (&udta->header, buffer, size, offset)) {
2731     return 0;
2732   }
2733   if (udta->meta) {
2734     if (!atom_meta_copy_data (udta->meta, buffer, size, offset)) {
2735       return 0;
2736     }
2737   }
2738   if (udta->entries) {
2739     /* extra atoms */
2740     if (!atom_info_list_copy_data (udta->entries, buffer, size, offset))
2741       return 0;
2742   }
2743
2744   atom_write_size (buffer, size, offset, original_offset);
2745   return *offset - original_offset;
2746 }
2747
2748 static guint64
2749 atom_mehd_copy_data (AtomMEHD * mehd, guint8 ** buffer, guint64 * size,
2750     guint64 * offset)
2751 {
2752   guint64 original_offset = *offset;
2753
2754   if (!atom_full_copy_data (&mehd->header, buffer, size, offset)) {
2755     return 0;
2756   }
2757
2758   prop_copy_uint64 (mehd->fragment_duration, buffer, size, offset);
2759
2760   atom_write_size (buffer, size, offset, original_offset);
2761   return *offset - original_offset;
2762 }
2763
2764 static guint64
2765 atom_trex_copy_data (AtomTREX * trex, guint8 ** buffer, guint64 * size,
2766     guint64 * offset)
2767 {
2768   guint64 original_offset = *offset;
2769
2770   if (!atom_full_copy_data (&trex->header, buffer, size, offset)) {
2771     return 0;
2772   }
2773
2774   prop_copy_uint32 (trex->track_ID, buffer, size, offset);
2775   prop_copy_uint32 (trex->default_sample_description_index, buffer, size,
2776       offset);
2777   prop_copy_uint32 (trex->default_sample_duration, buffer, size, offset);
2778   prop_copy_uint32 (trex->default_sample_size, buffer, size, offset);
2779   prop_copy_uint32 (trex->default_sample_flags, buffer, size, offset);
2780
2781   atom_write_size (buffer, size, offset, original_offset);
2782   return *offset - original_offset;
2783 }
2784
2785 static guint64
2786 atom_mvex_copy_data (AtomMVEX * mvex, guint8 ** buffer, guint64 * size,
2787     guint64 * offset)
2788 {
2789   guint64 original_offset = *offset;
2790   GList *walker;
2791
2792   if (!atom_copy_data (&mvex->header, buffer, size, offset)) {
2793     return 0;
2794   }
2795
2796   if (!atom_mehd_copy_data (&mvex->mehd, buffer, size, offset)) {
2797     return 0;
2798   }
2799
2800   walker = g_list_first (mvex->trexs);
2801   while (walker != NULL) {
2802     if (!atom_trex_copy_data ((AtomTREX *) walker->data, buffer, size, offset)) {
2803       return 0;
2804     }
2805     walker = g_list_next (walker);
2806   }
2807
2808   atom_write_size (buffer, size, offset, original_offset);
2809   return *offset - original_offset;
2810 }
2811
2812 guint64
2813 atom_trak_copy_data (AtomTRAK * trak, guint8 ** buffer, guint64 * size,
2814     guint64 * offset)
2815 {
2816   guint64 original_offset = *offset;
2817
2818   if (!atom_copy_data (&trak->header, buffer, size, offset)) {
2819     return 0;
2820   }
2821   if (!atom_tkhd_copy_data (&trak->tkhd, buffer, size, offset)) {
2822     return 0;
2823   }
2824   if (trak->tapt) {
2825     if (!trak->tapt->copy_data_func (trak->tapt->atom, buffer, size, offset)) {
2826       return 0;
2827     }
2828   }
2829   if (trak->edts) {
2830     if (!atom_edts_copy_data (trak->edts, buffer, size, offset)) {
2831       return 0;
2832     }
2833   }
2834   if (trak->tref) {
2835     /* Make sure we need this atom (there is a referenced track */
2836     if (atom_array_get_len (&trak->tref->entries) > 0) {
2837       if (!atom_tref_copy_data (trak->tref, buffer, size, offset)) {
2838         return 0;
2839       }
2840     }
2841   }
2842
2843   if (!atom_mdia_copy_data (&trak->mdia, buffer, size, offset)) {
2844     return 0;
2845   }
2846
2847   if (!atom_udta_copy_data (&trak->udta, buffer, size, offset)) {
2848     return 0;
2849   }
2850
2851   atom_write_size (buffer, size, offset, original_offset);
2852   return *offset - original_offset;
2853 }
2854
2855
2856 guint64
2857 atom_moov_copy_data (AtomMOOV * atom, guint8 ** buffer, guint64 * size,
2858     guint64 * offset)
2859 {
2860   guint64 original_offset = *offset;
2861   GList *walker;
2862
2863   if (!atom_copy_data (&(atom->header), buffer, size, offset))
2864     return 0;
2865
2866   if (!atom_mvhd_copy_data (&(atom->mvhd), buffer, size, offset))
2867     return 0;
2868
2869   walker = g_list_first (atom->traks);
2870   while (walker != NULL) {
2871     if (!atom_trak_copy_data ((AtomTRAK *) walker->data, buffer, size, offset)) {
2872       return 0;
2873     }
2874     walker = g_list_next (walker);
2875   }
2876
2877   if (!atom_udta_copy_data (&atom->udta, buffer, size, offset)) {
2878     return 0;
2879   }
2880
2881   if (atom->fragmented) {
2882     if (!atom_mvex_copy_data (&atom->mvex, buffer, size, offset)) {
2883       return 0;
2884     }
2885   }
2886
2887   atom_write_size (buffer, size, offset, original_offset);
2888   return *offset - original_offset;
2889 }
2890
2891 static guint64
2892 atom_wave_copy_data (AtomWAVE * wave, guint8 ** buffer,
2893     guint64 * size, guint64 * offset)
2894 {
2895   guint64 original_offset = *offset;
2896
2897   if (!atom_copy_data (&(wave->header), buffer, size, offset))
2898     return 0;
2899
2900   if (wave->extension_atoms) {
2901     if (!atom_info_list_copy_data (wave->extension_atoms, buffer, size, offset))
2902       return 0;
2903   }
2904
2905   atom_write_size (buffer, size, offset, original_offset);
2906   return *offset - original_offset;
2907 }
2908
2909 /* -- end of copy data functions -- */
2910
2911 /* -- general functions, API and support functions */
2912
2913 /* add samples to tables */
2914
2915 static void
2916 atom_stsc_add_new_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
2917 {
2918   gint len;
2919
2920   if ((len = atom_array_get_len (&stsc->entries)) > 1 &&
2921       ((atom_array_index (&stsc->entries, len - 1)).samples_per_chunk ==
2922           (atom_array_index (&stsc->entries, len - 2)).samples_per_chunk)) {
2923     STSCEntry *nentry;
2924
2925     /* Merge last two entries as they have the same number of samples per chunk */
2926     nentry = &atom_array_index (&stsc->entries, len - 1);
2927     nentry->first_chunk = first_chunk;
2928     nentry->samples_per_chunk = nsamples;
2929     nentry->sample_description_index = 1;
2930   } else {
2931     STSCEntry nentry;
2932
2933     nentry.first_chunk = first_chunk;
2934     nentry.samples_per_chunk = nsamples;
2935     nentry.sample_description_index = 1;
2936     atom_array_append (&stsc->entries, nentry, 128);
2937   }
2938 }
2939
2940 static void
2941 atom_stsc_update_entry (AtomSTSC * stsc, guint32 first_chunk, guint32 nsamples)
2942 {
2943   gint len;
2944
2945   len = atom_array_get_len (&stsc->entries);
2946   g_assert (len != 0);
2947   g_assert (atom_array_index (&stsc->entries,
2948           len - 1).first_chunk == first_chunk);
2949
2950   atom_array_index (&stsc->entries, len - 1).samples_per_chunk += nsamples;
2951 }
2952
2953 static void
2954 atom_stts_add_entry (AtomSTTS * stts, guint32 sample_count, gint32 sample_delta)
2955 {
2956   STTSEntry *entry = NULL;
2957
2958   if (G_LIKELY (atom_array_get_len (&stts->entries) != 0))
2959     entry = &atom_array_index (&stts->entries,
2960         atom_array_get_len (&stts->entries) - 1);
2961
2962   if (entry && entry->sample_delta == sample_delta) {
2963     entry->sample_count += sample_count;
2964   } else {
2965     STTSEntry nentry;
2966
2967     nentry.sample_count = sample_count;
2968     nentry.sample_delta = sample_delta;
2969     atom_array_append (&stts->entries, nentry, 256);
2970   }
2971 }
2972
2973 static void
2974 atom_stsz_add_entry (AtomSTSZ * stsz, guint32 nsamples, guint32 size)
2975 {
2976   guint32 i;
2977
2978   stsz->table_size += nsamples;
2979   if (stsz->sample_size != 0) {
2980     /* it is constant size, we don't need entries */
2981     return;
2982   }
2983   for (i = 0; i < nsamples; i++) {
2984     atom_array_append (&stsz->entries, size, 1024);
2985   }
2986 }
2987
2988 static guint32
2989 atom_stco64_get_entry_count (AtomSTCO64 * stco64)
2990 {
2991   return atom_array_get_len (&stco64->entries);
2992 }
2993
2994 /* returns TRUE if a new entry was added */
2995 static gboolean
2996 atom_stco64_add_entry (AtomSTCO64 * stco64, guint64 entry)
2997 {
2998   guint32 len;
2999
3000   /* Only add a new entry if the chunk offset changed */
3001   if ((len = atom_array_get_len (&stco64->entries)) &&
3002       ((atom_array_index (&stco64->entries, len - 1)) == entry))
3003     return FALSE;
3004
3005   atom_array_append (&stco64->entries, entry, 256);
3006   if (entry > G_MAXUINT32)
3007     stco64->header.header.type = FOURCC_co64;
3008
3009   return TRUE;
3010 }
3011
3012 void
3013 atom_tref_add_entry (AtomTREF * tref, guint32 sample)
3014 {
3015   atom_array_append (&tref->entries, sample, 512);
3016 }
3017
3018 static void
3019 atom_stss_add_entry (AtomSTSS * stss, guint32 sample)
3020 {
3021   atom_array_append (&stss->entries, sample, 512);
3022 }
3023
3024 static void
3025 atom_stbl_add_stss_entry (AtomSTBL * stbl)
3026 {
3027   guint32 sample_index = stbl->stsz.table_size;
3028
3029   atom_stss_add_entry (&stbl->stss, sample_index);
3030 }
3031
3032 static void
3033 atom_ctts_add_entry (AtomCTTS * ctts, guint32 nsamples, guint32 offset)
3034 {
3035   CTTSEntry *entry = NULL;
3036
3037   if (G_LIKELY (atom_array_get_len (&ctts->entries) != 0))
3038     entry = &atom_array_index (&ctts->entries,
3039         atom_array_get_len (&ctts->entries) - 1);
3040
3041   if (entry == NULL || entry->sampleoffset != offset) {
3042     CTTSEntry nentry;
3043
3044     nentry.samplecount = nsamples;
3045     nentry.sampleoffset = offset;
3046     atom_array_append (&ctts->entries, nentry, 256);
3047     if (offset != 0)
3048       ctts->do_pts = TRUE;
3049   } else {
3050     entry->samplecount += nsamples;
3051   }
3052 }
3053
3054 static void
3055 atom_stbl_add_ctts_entry (AtomSTBL * stbl, guint32 nsamples, guint32 offset)
3056 {
3057   if (stbl->ctts == NULL) {
3058     stbl->ctts = atom_ctts_new ();
3059   }
3060   atom_ctts_add_entry (stbl->ctts, nsamples, offset);
3061 }
3062
3063 void
3064 atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta,
3065     guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset)
3066 {
3067   atom_stts_add_entry (&stbl->stts, nsamples, delta);
3068   atom_stsz_add_entry (&stbl->stsz, nsamples, size);
3069   if (atom_stco64_add_entry (&stbl->stco64, chunk_offset)) {
3070     atom_stsc_add_new_entry (&stbl->stsc,
3071         atom_stco64_get_entry_count (&stbl->stco64), nsamples);
3072   } else {
3073     atom_stsc_update_entry (&stbl->stsc,
3074         atom_stco64_get_entry_count (&stbl->stco64), nsamples);
3075   }
3076
3077   if (sync)
3078     atom_stbl_add_stss_entry (stbl);
3079   /* always store to arrange for consistent content */
3080   atom_stbl_add_ctts_entry (stbl, nsamples, pts_offset);
3081 }
3082
3083 void
3084 atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta,
3085     guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset)
3086 {
3087   AtomSTBL *stbl = &trak->mdia.minf.stbl;
3088   atom_stbl_add_samples (stbl, nsamples, delta, size, chunk_offset, sync,
3089       pts_offset);
3090 }
3091
3092 /* trak and moov molding */
3093
3094 guint32
3095 atom_trak_get_timescale (AtomTRAK * trak)
3096 {
3097   return trak->mdia.mdhd.time_info.timescale;
3098 }
3099
3100 guint32
3101 atom_trak_get_id (AtomTRAK * trak)
3102 {
3103   return trak->tkhd.track_ID;
3104 }
3105
3106 static void
3107 atom_trak_set_id (AtomTRAK * trak, guint32 id)
3108 {
3109   trak->tkhd.track_ID = id;
3110 }
3111
3112 static void
3113 atom_moov_add_trex (AtomMOOV * moov, AtomTREX * trex)
3114 {
3115   moov->mvex.trexs = g_list_append (moov->mvex.trexs, trex);
3116 }
3117
3118 static AtomTREX *
3119 atom_trex_new (AtomTRAK * trak)
3120 {
3121   guint8 flags[3] = { 0, 0, 0 };
3122   AtomTREX *trex = g_new0 (AtomTREX, 1);
3123
3124   atom_full_init (&trex->header, FOURCC_trex, 0, 0, 0, flags);
3125
3126   trex->track_ID = trak->tkhd.track_ID;
3127   trex->default_sample_description_index = 1;
3128   trex->default_sample_duration = 0;
3129   trex->default_sample_size = 0;
3130   trex->default_sample_flags = 0;
3131
3132   return trex;
3133 }
3134
3135 void
3136 atom_moov_add_trak (AtomMOOV * moov, AtomTRAK * trak)
3137 {
3138   atom_trak_set_id (trak, moov->mvhd.next_track_id++);
3139   moov->traks = g_list_append (moov->traks, trak);
3140   /* additional trak means also new trex */
3141   atom_moov_add_trex (moov, atom_trex_new (trak));
3142 }
3143
3144 guint
3145 atom_moov_get_trak_count (AtomMOOV * moov)
3146 {
3147   return g_list_length (moov->traks);
3148 }
3149
3150 static guint64
3151 atom_trak_get_duration (AtomTRAK * trak)
3152 {
3153   return trak->tkhd.duration;
3154 }
3155
3156 static guint64
3157 atom_stts_get_total_duration (AtomSTTS * stts)
3158 {
3159   guint i;
3160   guint64 sum = 0;
3161
3162   for (i = 0; i < atom_array_get_len (&stts->entries); i++) {
3163     STTSEntry *entry = &atom_array_index (&stts->entries, i);
3164
3165     sum += (guint64) (entry->sample_count) * entry->sample_delta;
3166   }
3167   return sum;
3168 }
3169
3170 static void
3171 atom_trak_update_duration (AtomTRAK * trak, guint64 moov_timescale)
3172 {
3173   trak->mdia.mdhd.time_info.duration =
3174       atom_stts_get_total_duration (&trak->mdia.minf.stbl.stts);
3175   if (trak->mdia.mdhd.time_info.timescale != 0) {
3176     trak->tkhd.duration =
3177         gst_util_uint64_scale (trak->mdia.mdhd.time_info.duration,
3178         moov_timescale, trak->mdia.mdhd.time_info.timescale);
3179   } else {
3180     trak->tkhd.duration = 0;
3181   }
3182 }
3183
3184 static void
3185 timecode_atom_trak_set_duration (AtomTRAK * trak, guint64 duration,
3186     guint64 timescale)
3187 {
3188   STTSEntry *entry;
3189   GList *iter;
3190
3191   /* Sanity checks to ensure we have a timecode */
3192   g_assert (trak->mdia.minf.gmhd != NULL);
3193   g_assert (atom_array_get_len (&trak->mdia.minf.stbl.stts.entries) == 1);
3194
3195   for (iter = trak->mdia.minf.stbl.stsd.entries; iter;
3196       iter = g_list_next (iter)) {
3197     SampleTableEntry *entry = iter->data;
3198     if (entry->kind == TIMECODE) {
3199       SampleTableEntryTMCD *tmcd = (SampleTableEntryTMCD *) entry;
3200
3201       duration = duration * tmcd->timescale / timescale;
3202       timescale = tmcd->timescale;
3203       break;
3204     }
3205   }
3206
3207   trak->tkhd.duration = duration;
3208   trak->mdia.mdhd.time_info.duration = duration;
3209   trak->mdia.mdhd.time_info.timescale = timescale;
3210
3211   entry = &atom_array_index (&trak->mdia.minf.stbl.stts.entries, 0);
3212   entry->sample_delta = duration;
3213 }
3214
3215 static guint32
3216 atom_moov_get_timescale (AtomMOOV * moov)
3217 {
3218   return moov->mvhd.time_info.timescale;
3219 }
3220
3221 void
3222 atom_moov_update_timescale (AtomMOOV * moov, guint32 timescale)
3223 {
3224   moov->mvhd.time_info.timescale = timescale;
3225 }
3226
3227 void
3228 atom_moov_update_duration (AtomMOOV * moov)
3229 {
3230   GList *traks = moov->traks;
3231   guint64 dur, duration = 0;
3232
3233   while (traks) {
3234     AtomTRAK *trak = (AtomTRAK *) traks->data;
3235
3236     /* Skip timecodes for now: they have a placeholder duration */
3237     if (trak->mdia.minf.gmhd == NULL) {
3238       atom_trak_update_duration (trak, atom_moov_get_timescale (moov));
3239       dur = atom_trak_get_duration (trak);
3240       if (dur > duration)
3241         duration = dur;
3242     }
3243     traks = g_list_next (traks);
3244   }
3245   /* Now update the duration of the timecodes */
3246   traks = moov->traks;
3247   while (traks) {
3248     AtomTRAK *trak = (AtomTRAK *) traks->data;
3249
3250     if (trak->mdia.minf.gmhd != NULL)
3251       timecode_atom_trak_set_duration (trak, duration,
3252           atom_moov_get_timescale (moov));
3253     traks = g_list_next (traks);
3254   }
3255   moov->mvhd.time_info.duration = duration;
3256   moov->mvex.mehd.fragment_duration = duration;
3257 }
3258
3259 void
3260 atom_moov_set_fragmented (AtomMOOV * moov, gboolean fragmented)
3261 {
3262   moov->fragmented = fragmented;
3263 }
3264
3265 void
3266 atom_stco64_chunks_set_offset (AtomSTCO64 * stco64, guint32 offset)
3267 {
3268   stco64->chunk_offset = offset;
3269 }
3270
3271 void
3272 atom_moov_chunks_set_offset (AtomMOOV * moov, guint32 offset)
3273 {
3274   GList *traks = moov->traks;
3275
3276   if (offset == moov->chunks_offset)
3277     return;                     /* Nothing to do */
3278
3279   while (traks) {
3280     AtomTRAK *trak = (AtomTRAK *) traks->data;
3281
3282     atom_stco64_chunks_set_offset (&trak->mdia.minf.stbl.stco64, offset);
3283     traks = g_list_next (traks);
3284   }
3285
3286   moov->chunks_offset = offset;
3287 }
3288
3289 void
3290 atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate,
3291     guint32 max_bitrate)
3292 {
3293   AtomESDS *esds = NULL;
3294   AtomData *btrt = NULL;
3295   AtomWAVE *wave = NULL;
3296   AtomSTSD *stsd;
3297   GList *iter;
3298   GList *extensioniter = NULL;
3299
3300   g_return_if_fail (trak != NULL);
3301
3302   if (avg_bitrate == 0 && max_bitrate == 0)
3303     return;
3304
3305   stsd = &trak->mdia.minf.stbl.stsd;
3306   for (iter = stsd->entries; iter; iter = g_list_next (iter)) {
3307     SampleTableEntry *entry = iter->data;
3308
3309     switch (entry->kind) {
3310       case AUDIO:{
3311         SampleTableEntryMP4A *audioentry = (SampleTableEntryMP4A *) entry;
3312         extensioniter = audioentry->extension_atoms;
3313         break;
3314       }
3315       case VIDEO:{
3316         SampleTableEntryMP4V *videoentry = (SampleTableEntryMP4V *) entry;
3317         extensioniter = videoentry->extension_atoms;
3318         break;
3319       }
3320       default:
3321         break;
3322     }
3323   }
3324
3325   for (; extensioniter; extensioniter = g_list_next (extensioniter)) {
3326     AtomInfo *atominfo = extensioniter->data;
3327     if (atominfo->atom->type == FOURCC_esds) {
3328       esds = (AtomESDS *) atominfo->atom;
3329     } else if (atominfo->atom->type == FOURCC_btrt) {
3330       btrt = (AtomData *) atominfo->atom;
3331     } else if (atominfo->atom->type == FOURCC_wave) {
3332       wave = (AtomWAVE *) atominfo->atom;
3333     }
3334   }
3335
3336   /* wave might have an esds internally */
3337   if (wave) {
3338     for (extensioniter = wave->extension_atoms; extensioniter;
3339         extensioniter = g_list_next (extensioniter)) {
3340       AtomInfo *atominfo = extensioniter->data;
3341       if (atominfo->atom->type == FOURCC_esds) {
3342         esds = (AtomESDS *) atominfo->atom;
3343         break;
3344       }
3345     }
3346   }
3347
3348   if (esds) {
3349     if (avg_bitrate && esds->es.dec_conf_desc.avg_bitrate == 0)
3350       esds->es.dec_conf_desc.avg_bitrate = avg_bitrate;
3351     if (max_bitrate && esds->es.dec_conf_desc.max_bitrate == 0)
3352       esds->es.dec_conf_desc.max_bitrate = max_bitrate;
3353   }
3354   if (btrt) {
3355     /* type(4bytes) + size(4bytes) + buffersize(4bytes) +
3356      * maxbitrate(bytes) + avgbitrate(bytes) */
3357     if (max_bitrate && GST_READ_UINT32_BE (btrt->data + 4) == 0)
3358       GST_WRITE_UINT32_BE (btrt->data + 4, max_bitrate);
3359     if (avg_bitrate && GST_READ_UINT32_BE (btrt->data + 8) == 0)
3360       GST_WRITE_UINT32_BE (btrt->data + 8, avg_bitrate);
3361   }
3362 }
3363
3364 void
3365 atom_trak_tx3g_update_dimension (AtomTRAK * trak, guint32 width, guint32 height)
3366 {
3367   AtomSTSD *stsd;
3368   GList *iter;
3369   SampleTableEntryTX3G *tx3g = NULL;
3370
3371   stsd = &trak->mdia.minf.stbl.stsd;
3372   for (iter = stsd->entries; iter && tx3g == NULL; iter = g_list_next (iter)) {
3373     SampleTableEntry *entry = iter->data;
3374
3375     switch (entry->kind) {
3376       case SUBTITLE:{
3377         tx3g = (SampleTableEntryTX3G *) entry;
3378         break;
3379       }
3380       default:
3381         break;
3382     }
3383   }
3384
3385   /* Currently we never set the vertical placement flag, so we don't
3386    * check for it to set the dimensions differently as the spec says.
3387    * Always do it for the not set case */
3388   if (tx3g) {
3389     tx3g->font_size = 0.05 * height;
3390
3391     height = 0.15 * height;
3392     trak->tkhd.width = width << 16;
3393     trak->tkhd.height = height << 16;
3394     tx3g->default_text_box = width | (height << 16);
3395   }
3396 }
3397
3398 /*
3399  * Meta tags functions
3400  */
3401 static void
3402 atom_tag_data_alloc_data (AtomTagData * data, guint size)
3403 {
3404   g_free (data->data);
3405   data->data = g_new0 (guint8, size);
3406   data->datalen = size;
3407 }
3408
3409 static void
3410 atom_udta_append_tag (AtomUDTA * udta, AtomInfo * tag)
3411 {
3412   GList **entries;
3413
3414   if (udta->meta)
3415     entries = &udta->meta->ilst->entries;
3416   else
3417     entries = &udta->entries;
3418   *entries = g_list_append (*entries, tag);
3419 }
3420
3421 void
3422 atom_udta_add_tag (AtomUDTA * udta, guint32 fourcc, guint32 flags,
3423     const guint8 * data, guint size)
3424 {
3425   AtomTag *tag;
3426   AtomTagData *tdata;
3427
3428   tag = atom_tag_new (fourcc, flags);
3429   tdata = &tag->data;
3430   atom_tag_data_alloc_data (tdata, size);
3431   memmove (tdata->data, data, size);
3432
3433   atom_udta_append_tag (udta,
3434       build_atom_info_wrapper ((Atom *) tag, atom_tag_copy_data,
3435           atom_tag_free));
3436 }
3437
3438 void
3439 atom_udta_add_str_tag (AtomUDTA * udta, guint32 fourcc, const gchar * value)
3440 {
3441   gint len = strlen (value);
3442
3443   if (len > 0)
3444     atom_udta_add_tag (udta, fourcc, METADATA_TEXT_FLAG, (guint8 *) value, len);
3445 }
3446
3447 void
3448 atom_udta_add_uint_tag (AtomUDTA * udta, guint32 fourcc, guint32 flags,
3449     guint32 value)
3450 {
3451   guint8 data[8] = { 0, };
3452
3453   if (flags) {
3454     GST_WRITE_UINT16_BE (data, value);
3455     atom_udta_add_tag (udta, fourcc, flags, data, 2);
3456   } else {
3457     GST_WRITE_UINT32_BE (data + 2, value);
3458     atom_udta_add_tag (udta, fourcc, flags, data, 8);
3459   }
3460 }
3461
3462 #define GST_BUFFER_NEW_READONLY(mem, size) \
3463     gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, mem, size, \
3464     0, size, mem, NULL)
3465
3466 void
3467 atom_udta_add_blob_tag (AtomUDTA * udta, guint8 * data, guint size)
3468 {
3469   AtomData *data_atom;
3470   guint len;
3471   guint32 fourcc;
3472
3473   if (size < 8)
3474     return;
3475
3476   /* blob is unparsed atom;
3477    * extract size and fourcc, and wrap remainder in data atom */
3478   len = GST_READ_UINT32_BE (data);
3479   fourcc = GST_READ_UINT32_LE (data + 4);
3480   if (len > size)
3481     return;
3482
3483   data_atom = atom_data_new_from_data (fourcc, data + 8, len - 8);
3484
3485   atom_udta_append_tag (udta,
3486       build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
3487           atom_data_free));
3488 }
3489
3490 void
3491 atom_udta_add_3gp_tag (AtomUDTA * udta, guint32 fourcc, guint8 * data,
3492     guint size)
3493 {
3494   AtomData *data_atom;
3495
3496   data_atom = atom_data_new (fourcc);
3497
3498   /* need full atom */
3499   atom_data_alloc_mem (data_atom, size + 4);
3500
3501   /* full atom: version and flags */
3502   GST_WRITE_UINT32_BE (data_atom->data, 0);
3503   memcpy (data_atom->data + 4, data, size);
3504
3505   atom_udta_append_tag (udta,
3506       build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
3507           atom_data_free));
3508 }
3509
3510 guint16
3511 language_code (const char *lang)
3512 {
3513   g_return_val_if_fail (lang != NULL, 0);
3514   g_return_val_if_fail (strlen (lang) == 3, 0);
3515
3516   return (((lang[0] - 0x60) & 0x1F) << 10) + (((lang[1] - 0x60) & 0x1F) << 5) +
3517       ((lang[2] - 0x60) & 0x1F);
3518 }
3519
3520 void
3521 atom_udta_add_3gp_str_int_tag (AtomUDTA * udta, guint32 fourcc,
3522     const gchar * value, gint16 ivalue)
3523 {
3524   gint len = 0, size = 0;
3525   guint8 *data;
3526
3527   if (value) {
3528     len = strlen (value);
3529     size = len + 3;
3530   }
3531
3532   if (ivalue >= 0)
3533     size += 2;
3534
3535   data = g_malloc (size + 3);
3536   /* language tag and null-terminated UTF-8 string */
3537   if (value) {
3538     GST_WRITE_UINT16_BE (data, language_code (GST_QT_MUX_DEFAULT_TAG_LANGUAGE));
3539     /* include 0 terminator */
3540     memcpy (data + 2, value, len + 1);
3541   }
3542   /* 16-bit unsigned int if standalone, otherwise 8-bit */
3543   if (ivalue >= 0) {
3544     if (size == 2)
3545       GST_WRITE_UINT16_BE (data + size - 2, ivalue);
3546     else {
3547       GST_WRITE_UINT8 (data + size - 2, ivalue & 0xFF);
3548       size--;
3549     }
3550   }
3551
3552   atom_udta_add_3gp_tag (udta, fourcc, data, size);
3553   g_free (data);
3554 }
3555
3556 void
3557 atom_udta_add_3gp_str_tag (AtomUDTA * udta, guint32 fourcc, const gchar * value)
3558 {
3559   atom_udta_add_3gp_str_int_tag (udta, fourcc, value, -1);
3560 }
3561
3562 void
3563 atom_udta_add_3gp_uint_tag (AtomUDTA * udta, guint32 fourcc, guint16 value)
3564 {
3565   atom_udta_add_3gp_str_int_tag (udta, fourcc, NULL, value);
3566 }
3567
3568 void
3569 atom_udta_add_xmp_tags (AtomUDTA * udta, GstBuffer * xmpbuffer)
3570 {
3571   AtomData *data_atom = NULL;
3572
3573   if (udta->context->flavor == ATOMS_TREE_FLAVOR_MOV) {
3574     if (xmpbuffer) {
3575       data_atom = atom_data_new_from_gst_buffer (FOURCC_XMP_, xmpbuffer);
3576       udta->entries = g_list_append (udta->entries,
3577           build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
3578               atom_data_free));
3579     }
3580   } else {
3581     GST_DEBUG ("Not adding xmp to moov atom, it is only used in 'mov' format");
3582   }
3583 }
3584
3585 /*
3586  * Functions for specifying media types
3587  */
3588
3589 static void
3590 atom_minf_set_audio (AtomMINF * minf)
3591 {
3592   atom_minf_clear_handlers (minf);
3593   minf->smhd = atom_smhd_new ();
3594 }
3595
3596 static void
3597 atom_minf_set_video (AtomMINF * minf, AtomsContext * context)
3598 {
3599   atom_minf_clear_handlers (minf);
3600   minf->vmhd = atom_vmhd_new (context);
3601 }
3602
3603 static void
3604 atom_minf_set_subtitle (AtomMINF * minf)
3605 {
3606   atom_minf_clear_handlers (minf);
3607 }
3608
3609 static void
3610 atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type,
3611     guint32 hdlr_type)
3612 {
3613   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
3614     hdlr->component_type = comp_type;
3615   }
3616   hdlr->handler_type = hdlr_type;
3617 }
3618
3619 static void
3620 atom_hdlr_set_name (AtomHDLR * hdlr, const char *name)
3621 {
3622   g_free (hdlr->name);
3623   hdlr->name = g_strdup (name);
3624 }
3625
3626 static void
3627 atom_mdia_set_hdlr_type_audio (AtomMDIA * mdia, AtomsContext * context)
3628 {
3629   atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_soun);
3630   /* Some players (low-end hardware) check for this name, which is what
3631    * QuickTime itself sets */
3632   atom_hdlr_set_name (&mdia->hdlr, "SoundHandler");
3633 }
3634
3635 static void
3636 atom_mdia_set_hdlr_type_video (AtomMDIA * mdia, AtomsContext * context)
3637 {
3638   atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_vide);
3639   /* Some players (low-end hardware) check for this name, which is what
3640    * QuickTime itself sets */
3641   atom_hdlr_set_name (&mdia->hdlr, "VideoHandler");
3642 }
3643
3644 static void
3645 atom_mdia_set_hdlr_type_subtitle (AtomMDIA * mdia, AtomsContext * context)
3646 {
3647   atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_sbtl);
3648
3649   /* Just follows the pattern from video and audio above */
3650   atom_hdlr_set_name (&mdia->hdlr, "SubtitleHandler");
3651 }
3652
3653 static void
3654 atom_mdia_set_audio (AtomMDIA * mdia, AtomsContext * context)
3655 {
3656   atom_mdia_set_hdlr_type_audio (mdia, context);
3657   atom_minf_set_audio (&mdia->minf);
3658 }
3659
3660 static void
3661 atom_mdia_set_video (AtomMDIA * mdia, AtomsContext * context)
3662 {
3663   atom_mdia_set_hdlr_type_video (mdia, context);
3664   atom_minf_set_video (&mdia->minf, context);
3665 }
3666
3667 static void
3668 atom_mdia_set_subtitle (AtomMDIA * mdia, AtomsContext * context)
3669 {
3670   atom_mdia_set_hdlr_type_subtitle (mdia, context);
3671   atom_minf_set_subtitle (&mdia->minf);
3672 }
3673
3674 static void
3675 atom_tkhd_set_audio (AtomTKHD * tkhd)
3676 {
3677   tkhd->volume = 0x0100;
3678   tkhd->width = tkhd->height = 0;
3679 }
3680
3681 static void
3682 atom_tkhd_set_video (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
3683     guint32 height)
3684 {
3685   tkhd->volume = 0;
3686
3687   /* qt and ISO base media do not contradict, and examples agree */
3688   tkhd->width = width;
3689   tkhd->height = height;
3690 }
3691
3692 static void
3693 atom_tkhd_set_subtitle (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
3694     guint32 height)
3695 {
3696   tkhd->volume = 0;
3697
3698   /* qt and ISO base media do not contradict, and examples agree */
3699   tkhd->width = width;
3700   tkhd->height = height;
3701 }
3702
3703
3704 static void
3705 atom_edts_add_entry (AtomEDTS * edts, gint index, EditListEntry * entry)
3706 {
3707   EditListEntry *e =
3708       (EditListEntry *) g_slist_nth_data (edts->elst.entries, index);
3709   /* Create a new entry if missing (appends to the list if index is larger) */
3710   if (e == NULL) {
3711     e = g_new (EditListEntry, 1);
3712     edts->elst.entries = g_slist_insert (edts->elst.entries, e, index);
3713   }
3714
3715   /* Update the entry */
3716   *e = *entry;
3717 }
3718
3719 void
3720 atom_trak_edts_clear (AtomTRAK * trak)
3721 {
3722   if (trak->edts) {
3723     atom_edts_clear (trak->edts);
3724     trak->edts = NULL;
3725   }
3726 }
3727
3728 /*
3729  * Update an entry in this trak edits list, creating it if needed.
3730  * index is the index of the entry to update, or create if it's past the end.
3731  * duration is in the moov's timescale
3732  * media_time is the offset in the media time to start from (media's timescale)
3733  * rate is a 32 bits fixed-point
3734  */
3735 void
3736 atom_trak_set_elst_entry (AtomTRAK * trak, gint index,
3737     guint32 duration, guint32 media_time, guint32 rate)
3738 {
3739   EditListEntry entry;
3740
3741   entry.duration = duration;
3742   entry.media_time = media_time;
3743   entry.media_rate = rate;
3744
3745   if (trak->edts == NULL)
3746     trak->edts = atom_edts_new ();
3747
3748   atom_edts_add_entry (trak->edts, index, &entry);
3749 }
3750
3751 /* re-negotiation is prevented at top-level, so only 1 entry expected.
3752  * Quite some more care here and elsewhere may be needed to
3753  * support several entries */
3754 static SampleTableEntryMP4A *
3755 atom_trak_add_audio_entry (AtomTRAK * trak, AtomsContext * context,
3756     guint32 type)
3757 {
3758   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
3759   SampleTableEntryMP4A *mp4a = sample_entry_mp4a_new ();
3760
3761   mp4a->se.header.type = type;
3762   mp4a->se.kind = AUDIO;
3763   mp4a->compression_id = -1;
3764   mp4a->se.data_reference_index = 1;
3765
3766   stsd->entries = g_list_prepend (stsd->entries, mp4a);
3767   stsd->n_entries++;
3768   return mp4a;
3769 }
3770
3771 static SampleTableEntryTMCD *
3772 atom_trak_add_timecode_entry (AtomTRAK * trak, AtomsContext * context,
3773     GstVideoTimeCode * tc)
3774 {
3775   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
3776   SampleTableEntryTMCD *tmcd = sample_entry_tmcd_new ();
3777
3778   trak->mdia.hdlr.component_type = FOURCC_mhlr;
3779   trak->mdia.hdlr.handler_type = FOURCC_tmcd;
3780   trak->mdia.hdlr.name = g_strdup ("Time Code Media Handler");
3781   trak->mdia.mdhd.time_info.timescale = tc->config.fps_n / tc->config.fps_d;
3782
3783   tmcd->se.kind = TIMECODE;
3784   tmcd->se.data_reference_index = 1;
3785   tmcd->tc_flags = TC_24H_MAX;
3786   if (tc->config.flags &= GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME)
3787     tmcd->tc_flags |= TC_DROP_FRAME;
3788   tmcd->name.language_code = 0;
3789   tmcd->name.name = g_strdup ("Tape");
3790   tmcd->timescale = tc->config.fps_n;
3791   tmcd->frame_duration = tc->config.fps_d;
3792   if (tc->config.fps_d == 1001)
3793     tmcd->n_frames = tc->config.fps_n / 1000;
3794   else
3795     tmcd->n_frames = tc->config.fps_n / tc->config.fps_d;
3796
3797   stsd->entries = g_list_prepend (stsd->entries, tmcd);
3798   stsd->n_entries++;
3799   return tmcd;
3800 }
3801
3802 static SampleTableEntryMP4V *
3803 atom_trak_add_video_entry (AtomTRAK * trak, AtomsContext * context,
3804     guint32 type)
3805 {
3806   SampleTableEntryMP4V *mp4v = sample_entry_mp4v_new (context);
3807   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
3808
3809   mp4v->se.header.type = type;
3810   mp4v->se.kind = VIDEO;
3811   mp4v->se.data_reference_index = 1;
3812   mp4v->horizontal_resolution = 72 << 16;
3813   mp4v->vertical_resolution = 72 << 16;
3814   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
3815     mp4v->spatial_quality = 512;
3816     mp4v->temporal_quality = 512;
3817   }
3818
3819   stsd->entries = g_list_prepend (stsd->entries, mp4v);
3820   stsd->n_entries++;
3821   return mp4v;
3822 }
3823
3824 static SampleTableEntryTX3G *
3825 atom_trak_add_subtitle_entry (AtomTRAK * trak, AtomsContext * context,
3826     guint32 type)
3827 {
3828   SampleTableEntryTX3G *tx3g = sample_entry_tx3g_new ();
3829   AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd;
3830
3831   tx3g->se.header.type = type;
3832   tx3g->se.kind = SUBTITLE;
3833   tx3g->se.data_reference_index = 1;
3834
3835   stsd->entries = g_list_prepend (stsd->entries, tx3g);
3836   stsd->n_entries++;
3837   return tx3g;
3838 }
3839
3840
3841 static void
3842 atom_trak_set_constant_size_samples (AtomTRAK * trak, guint32 sample_size)
3843 {
3844   trak->mdia.minf.stbl.stsz.sample_size = sample_size;
3845 }
3846
3847 static void
3848 atom_trak_set_audio (AtomTRAK * trak, AtomsContext * context)
3849 {
3850   atom_tkhd_set_audio (&trak->tkhd);
3851   atom_mdia_set_audio (&trak->mdia, context);
3852 }
3853
3854 static void
3855 atom_trak_set_video (AtomTRAK * trak, AtomsContext * context, guint32 width,
3856     guint32 height)
3857 {
3858   atom_tkhd_set_video (&trak->tkhd, context, width, height);
3859   atom_mdia_set_video (&trak->mdia, context);
3860 }
3861
3862 static void
3863 atom_trak_set_subtitle (AtomTRAK * trak, AtomsContext * context)
3864 {
3865   atom_tkhd_set_subtitle (&trak->tkhd, context, 0, 0);
3866   atom_mdia_set_subtitle (&trak->mdia, context);
3867 }
3868
3869 static void
3870 atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context,
3871     guint32 rate)
3872 {
3873   atom_trak_set_audio (trak, context);
3874   trak->mdia.mdhd.time_info.timescale = rate;
3875 }
3876
3877 static void
3878 atom_trak_set_video_commons (AtomTRAK * trak, AtomsContext * context,
3879     guint32 rate, guint32 width, guint32 height)
3880 {
3881   atom_trak_set_video (trak, context, width, height);
3882   trak->mdia.mdhd.time_info.timescale = rate;
3883   trak->tkhd.width = width << 16;
3884   trak->tkhd.height = height << 16;
3885 }
3886
3887 static void
3888 atom_trak_set_subtitle_commons (AtomTRAK * trak, AtomsContext * context)
3889 {
3890   atom_trak_set_subtitle (trak, context);
3891   trak->mdia.mdhd.time_info.timescale = 1000;
3892
3893   trak->tkhd.alternate_group = 2;       /* same for all subtitles */
3894   trak->tkhd.layer = -1;        /* above video (layer 0) */
3895 }
3896
3897 void
3898 sample_table_entry_add_ext_atom (SampleTableEntry * ste, AtomInfo * ext)
3899 {
3900   GList **list = NULL;
3901   if (ste->kind == AUDIO) {
3902     list = &(((SampleTableEntryMP4A *) ste)->extension_atoms);
3903   } else if (ste->kind == VIDEO) {
3904     list = &(((SampleTableEntryMP4V *) ste)->extension_atoms);
3905   } else {
3906     g_assert_not_reached ();
3907     return;
3908   }
3909
3910   *list = g_list_prepend (*list, ext);
3911 }
3912
3913 SampleTableEntryMP4A *
3914 atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
3915     AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size)
3916 {
3917   SampleTableEntryMP4A *ste;
3918
3919   atom_trak_set_audio_commons (trak, context, scale);
3920   atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
3921   ste = atom_trak_add_audio_entry (trak, context, entry->fourcc);
3922
3923   trak->is_video = FALSE;
3924   trak->is_h264 = FALSE;
3925
3926   ste->version = entry->version;
3927   ste->compression_id = entry->compression_id;
3928   ste->sample_size = entry->sample_size;
3929   ste->sample_rate = entry->sample_rate << 16;
3930   ste->channels = entry->channels;
3931
3932   ste->samples_per_packet = entry->samples_per_packet;
3933   ste->bytes_per_sample = entry->bytes_per_sample;
3934   ste->bytes_per_packet = entry->bytes_per_packet;
3935   ste->bytes_per_frame = entry->bytes_per_frame;
3936
3937   if (ext)
3938     ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext);
3939
3940   /* 0 size means variable size */
3941   atom_trak_set_constant_size_samples (trak, sample_size);
3942
3943   return ste;
3944 }
3945
3946 SampleTableEntryTMCD *
3947 atom_trak_set_timecode_type (AtomTRAK * trak, AtomsContext * context,
3948     GstVideoTimeCode * tc)
3949 {
3950   SampleTableEntryTMCD *ste;
3951   AtomGMHD *gmhd = trak->mdia.minf.gmhd;
3952
3953   if (context->flavor != ATOMS_TREE_FLAVOR_MOV) {
3954     return NULL;
3955   }
3956
3957   ste = atom_trak_add_timecode_entry (trak, context, tc);
3958
3959   gmhd = atom_gmhd_new ();
3960   gmhd->gmin.graphics_mode = 0x0040;
3961   gmhd->gmin.opcolor[0] = 0x8000;
3962   gmhd->gmin.opcolor[1] = 0x8000;
3963   gmhd->gmin.opcolor[2] = 0x8000;
3964   gmhd->tmcd.tcmi.text_size = 12;
3965   gmhd->tmcd.tcmi.font_name = g_strdup ("Chicago");     /* Pascal string */
3966
3967   trak->mdia.minf.gmhd = gmhd;
3968   trak->is_video = FALSE;
3969   trak->is_h264 = FALSE;
3970
3971   return ste;
3972 }
3973
3974 static AtomInfo *
3975 build_pasp_extension (gint par_width, gint par_height)
3976 {
3977   AtomData *atom_data = atom_data_new (FOURCC_pasp);
3978   guint8 *data;
3979
3980   atom_data_alloc_mem (atom_data, 8);
3981   data = atom_data->data;
3982
3983   /* ihdr = image header box */
3984   GST_WRITE_UINT32_BE (data, par_width);
3985   GST_WRITE_UINT32_BE (data + 4, par_height);
3986
3987   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
3988       atom_data_free);
3989 }
3990
3991 AtomInfo *
3992 build_fiel_extension (GstVideoInterlaceMode mode, GstVideoFieldOrder order)
3993 {
3994   AtomData *atom_data = atom_data_new (FOURCC_fiel);
3995   guint8 *data;
3996   gint field_order;
3997   gint interlace;
3998
3999   atom_data_alloc_mem (atom_data, 2);
4000   data = atom_data->data;
4001
4002   if (mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE) {
4003     interlace = 1;
4004     field_order = 0;
4005   } else if (mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) {
4006     interlace = 2;
4007     field_order = order == GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST ? 9 : 14;
4008   } else {
4009     interlace = 0;
4010     field_order = 0;
4011   }
4012
4013   GST_WRITE_UINT8 (data, interlace);
4014   GST_WRITE_UINT8 (data + 1, field_order);
4015
4016   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4017       atom_data_free);
4018 }
4019
4020 AtomInfo *
4021 build_colr_extension (const GstVideoColorimetry * colorimetry, gboolean is_mp4)
4022 {
4023   AtomData *atom_data = atom_data_new (FOURCC_colr);
4024   guint8 *data;
4025   guint16 primaries;
4026   guint16 transfer_function;
4027   guint16 matrix;
4028
4029   switch (colorimetry->primaries) {
4030     case GST_VIDEO_COLOR_PRIMARIES_BT709:
4031       primaries = 1;
4032       break;
4033     case GST_VIDEO_COLOR_PRIMARIES_BT470BG:
4034       primaries = 5;
4035       break;
4036     case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M:
4037     case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M:
4038       primaries = 6;
4039       break;
4040     case GST_VIDEO_COLOR_PRIMARIES_BT2020:
4041       primaries = 9;
4042       break;
4043     case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN:
4044     default:
4045       primaries = 2;
4046       break;
4047   }
4048
4049   switch (colorimetry->transfer) {
4050     case GST_VIDEO_TRANSFER_BT709:
4051       transfer_function = 1;
4052       break;
4053     case GST_VIDEO_TRANSFER_SMPTE240M:
4054       transfer_function = 7;
4055       break;
4056     case GST_VIDEO_TRANSFER_UNKNOWN:
4057     default:
4058       transfer_function = 2;
4059       break;
4060   }
4061
4062   switch (colorimetry->matrix) {
4063     case GST_VIDEO_COLOR_MATRIX_BT709:
4064       matrix = 1;
4065       break;
4066     case GST_VIDEO_COLOR_MATRIX_BT601:
4067       matrix = 6;
4068       break;
4069     case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
4070       matrix = 7;
4071       break;
4072     case GST_VIDEO_COLOR_MATRIX_BT2020:
4073       matrix = 9;
4074       break;
4075     case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
4076     default:
4077       matrix = 2;
4078       break;
4079   }
4080
4081   atom_data_alloc_mem (atom_data, 10 + (is_mp4 ? 1 : 0));
4082   data = atom_data->data;
4083
4084   /* colour specification box */
4085   if (is_mp4)
4086     GST_WRITE_UINT32_LE (data, FOURCC_nclx);
4087   else
4088     GST_WRITE_UINT32_LE (data, FOURCC_nclc);
4089
4090   GST_WRITE_UINT16_BE (data + 4, primaries);
4091   GST_WRITE_UINT16_BE (data + 6, transfer_function);
4092   GST_WRITE_UINT16_BE (data + 8, matrix);
4093
4094   if (is_mp4) {
4095     GST_WRITE_UINT8 (data + 10,
4096         colorimetry->range == GST_VIDEO_COLOR_RANGE_0_255 ? 0x80 : 0x00);
4097   }
4098
4099   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4100       atom_data_free);
4101 }
4102
4103 AtomInfo *
4104 build_clap_extension (gint width_n, gint width_d, gint height_n, gint height_d,
4105     gint h_off_n, gint h_off_d, gint v_off_n, gint v_off_d)
4106 {
4107   AtomData *atom_data = atom_data_new (FOURCC_clap);
4108   guint8 *data;
4109
4110   atom_data_alloc_mem (atom_data, 32);
4111   data = atom_data->data;
4112
4113   GST_WRITE_UINT32_BE (data, width_n);
4114   GST_WRITE_UINT32_BE (data + 4, width_d);
4115   GST_WRITE_UINT32_BE (data + 8, height_n);
4116   GST_WRITE_UINT32_BE (data + 12, height_d);
4117   GST_WRITE_UINT32_BE (data + 16, h_off_n);
4118   GST_WRITE_UINT32_BE (data + 20, h_off_d);
4119   GST_WRITE_UINT32_BE (data + 24, v_off_n);
4120   GST_WRITE_UINT32_BE (data + 28, v_off_d);
4121
4122   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4123       atom_data_free);
4124 }
4125
4126 AtomInfo *
4127 build_tapt_extension (gint clef_width, gint clef_height, gint prof_width,
4128     gint prof_height, gint enof_width, gint enof_height)
4129 {
4130   AtomData *atom_data = atom_data_new (FOURCC_tapt);
4131   guint8 *data;
4132
4133   atom_data_alloc_mem (atom_data, 60);
4134   data = atom_data->data;
4135
4136   GST_WRITE_UINT32_BE (data, 20);
4137   GST_WRITE_UINT32_LE (data + 4, FOURCC_clef);
4138   GST_WRITE_UINT32_BE (data + 8, 0);
4139   GST_WRITE_UINT32_BE (data + 12, clef_width);
4140   GST_WRITE_UINT32_BE (data + 16, clef_height);
4141
4142   GST_WRITE_UINT32_BE (data + 20, 20);
4143   GST_WRITE_UINT32_LE (data + 24, FOURCC_prof);
4144   GST_WRITE_UINT32_BE (data + 28, 0);
4145   GST_WRITE_UINT32_BE (data + 32, prof_width);
4146   GST_WRITE_UINT32_BE (data + 36, prof_height);
4147
4148   GST_WRITE_UINT32_BE (data + 40, 20);
4149   GST_WRITE_UINT32_LE (data + 44, FOURCC_enof);
4150   GST_WRITE_UINT32_BE (data + 48, 0);
4151   GST_WRITE_UINT32_BE (data + 52, enof_width);
4152   GST_WRITE_UINT32_BE (data + 56, enof_height);
4153
4154
4155   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
4156       atom_data_free);
4157 }
4158
4159 static AtomInfo *
4160 build_mov_video_sample_description_padding_extension (void)
4161 {
4162   AtomData *atom_data = atom_data_new (FOURCC_clap);
4163
4164   return build_atom_info_wrapper ((Atom *) atom_data, atom_copy_empty,
4165       atom_data_free);
4166 }
4167
4168 SampleTableEntryMP4V *
4169 atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
4170     VisualSampleEntry * entry, guint32 scale, GList * ext_atoms_list)
4171 {
4172   SampleTableEntryMP4V *ste;
4173   guint dwidth, dheight;
4174   gint par_n = 0, par_d = 0;
4175
4176   par_n = entry->par_n;
4177   par_d = entry->par_d;
4178
4179   dwidth = entry->width;
4180   dheight = entry->height;
4181   /* ISO file spec says track header w/h indicates track's visual presentation
4182    * (so this together with pixels w/h implicitly defines PAR) */
4183   if (par_n && (context->flavor != ATOMS_TREE_FLAVOR_MOV)) {
4184     /* Assumes square pixels display */
4185     if (!gst_video_calculate_display_ratio (&dwidth, &dheight, entry->width,
4186             entry->height, par_n, par_d, 1, 1)) {
4187       GST_WARNING ("Could not calculate display ratio");
4188     }
4189   }
4190
4191   atom_trak_set_video_commons (trak, context, scale, dwidth, dheight);
4192   atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
4193   ste = atom_trak_add_video_entry (trak, context, entry->fourcc);
4194
4195   trak->is_video = TRUE;
4196   trak->is_h264 = (entry->fourcc == FOURCC_avc1
4197       || entry->fourcc == FOURCC_avc3);
4198
4199   ste->version = entry->version;
4200   ste->width = entry->width;
4201   ste->height = entry->height;
4202   ste->depth = entry->depth;
4203   ste->color_table_id = entry->color_table_id;
4204   ste->frame_count = entry->frame_count;
4205
4206   if (ext_atoms_list)
4207     ste->extension_atoms = g_list_concat (ste->extension_atoms, ext_atoms_list);
4208
4209   ste->extension_atoms = g_list_append (ste->extension_atoms,
4210       build_pasp_extension (par_n, par_d));
4211
4212   if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
4213     /* append 0 as a terminator "length" to work around some broken software */
4214     ste->extension_atoms =
4215         g_list_append (ste->extension_atoms,
4216         build_mov_video_sample_description_padding_extension ());
4217   }
4218
4219   return ste;
4220 }
4221
4222 void
4223 subtitle_sample_entry_init (SubtitleSampleEntry * entry)
4224 {
4225   entry->font_size = 0;
4226   entry->font_face = 0;
4227   entry->foreground_color_rgba = 0xFFFFFFFF;    /* all white, opaque */
4228 }
4229
4230 SampleTableEntryTX3G *
4231 atom_trak_set_subtitle_type (AtomTRAK * trak, AtomsContext * context,
4232     SubtitleSampleEntry * entry)
4233 {
4234   SampleTableEntryTX3G *tx3g;
4235
4236   atom_trak_set_subtitle_commons (trak, context);
4237   atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd);
4238   tx3g = atom_trak_add_subtitle_entry (trak, context, entry->fourcc);
4239
4240   tx3g->font_face = entry->font_face;
4241   tx3g->font_size = entry->font_size;
4242   tx3g->foreground_color_rgba = entry->foreground_color_rgba;
4243
4244   trak->is_video = FALSE;
4245   trak->is_h264 = FALSE;
4246
4247   return tx3g;
4248 }
4249
4250 static void
4251 atom_mfhd_init (AtomMFHD * mfhd, guint32 sequence_number)
4252 {
4253   guint8 flags[3] = { 0, 0, 0 };
4254
4255   atom_full_init (&(mfhd->header), FOURCC_mfhd, 0, 0, 0, flags);
4256   mfhd->sequence_number = sequence_number;
4257 }
4258
4259 static void
4260 atom_moof_init (AtomMOOF * moof, AtomsContext * context,
4261     guint32 sequence_number)
4262 {
4263   atom_header_set (&moof->header, FOURCC_moof, 0, 0);
4264   atom_mfhd_init (&moof->mfhd, sequence_number);
4265   moof->trafs = NULL;
4266 }
4267
4268 AtomMOOF *
4269 atom_moof_new (AtomsContext * context, guint32 sequence_number)
4270 {
4271   AtomMOOF *moof = g_new0 (AtomMOOF, 1);
4272
4273   atom_moof_init (moof, context, sequence_number);
4274   return moof;
4275 }
4276
4277 static void
4278 atom_trun_free (AtomTRUN * trun)
4279 {
4280   atom_full_clear (&trun->header);
4281   atom_array_clear (&trun->entries);
4282   g_free (trun);
4283 }
4284
4285 static void
4286 atom_sdtp_free (AtomSDTP * sdtp)
4287 {
4288   atom_full_clear (&sdtp->header);
4289   atom_array_clear (&sdtp->entries);
4290   g_free (sdtp);
4291 }
4292
4293 void
4294 atom_traf_free (AtomTRAF * traf)
4295 {
4296   GList *walker;
4297
4298   walker = traf->truns;
4299   while (walker) {
4300     atom_trun_free ((AtomTRUN *) walker->data);
4301     walker = g_list_next (walker);
4302   }
4303   g_list_free (traf->truns);
4304   traf->truns = NULL;
4305
4306   walker = traf->sdtps;
4307   while (walker) {
4308     atom_sdtp_free ((AtomSDTP *) walker->data);
4309     walker = g_list_next (walker);
4310   }
4311   g_list_free (traf->sdtps);
4312   traf->sdtps = NULL;
4313
4314   g_free (traf);
4315 }
4316
4317 void
4318 atom_moof_free (AtomMOOF * moof)
4319 {
4320   GList *walker;
4321
4322   walker = moof->trafs;
4323   while (walker) {
4324     atom_traf_free ((AtomTRAF *) walker->data);
4325     walker = g_list_next (walker);
4326   }
4327   g_list_free (moof->trafs);
4328   moof->trafs = NULL;
4329
4330   g_free (moof);
4331 }
4332
4333 static guint64
4334 atom_mfhd_copy_data (AtomMFHD * mfhd, guint8 ** buffer, guint64 * size,
4335     guint64 * offset)
4336 {
4337   guint64 original_offset = *offset;
4338
4339   if (!atom_full_copy_data (&mfhd->header, buffer, size, offset)) {
4340     return 0;
4341   }
4342
4343   prop_copy_uint32 (mfhd->sequence_number, buffer, size, offset);
4344
4345   atom_write_size (buffer, size, offset, original_offset);
4346   return *offset - original_offset;
4347 }
4348
4349 static guint64
4350 atom_tfhd_copy_data (AtomTFHD * tfhd, guint8 ** buffer, guint64 * size,
4351     guint64 * offset)
4352 {
4353   guint64 original_offset = *offset;
4354   guint32 flags;
4355
4356   if (!atom_full_copy_data (&tfhd->header, buffer, size, offset)) {
4357     return 0;
4358   }
4359
4360   prop_copy_uint32 (tfhd->track_ID, buffer, size, offset);
4361
4362   flags = atom_full_get_flags_as_uint (&tfhd->header);
4363
4364   if (flags & TF_BASE_DATA_OFFSET)
4365     prop_copy_uint64 (tfhd->base_data_offset, buffer, size, offset);
4366   if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
4367     prop_copy_uint32 (tfhd->sample_description_index, buffer, size, offset);
4368   if (flags & TF_DEFAULT_SAMPLE_DURATION)
4369     prop_copy_uint32 (tfhd->default_sample_duration, buffer, size, offset);
4370   if (flags & TF_DEFAULT_SAMPLE_SIZE)
4371     prop_copy_uint32 (tfhd->default_sample_size, buffer, size, offset);
4372   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
4373     prop_copy_uint32 (tfhd->default_sample_flags, buffer, size, offset);
4374
4375   atom_write_size (buffer, size, offset, original_offset);
4376   return *offset - original_offset;
4377 }
4378
4379 static guint64
4380 atom_tfdt_copy_data (AtomTFDT * tfdt, guint8 ** buffer, guint64 * size,
4381     guint64 * offset)
4382 {
4383   guint64 original_offset = *offset;
4384
4385   if (!atom_full_copy_data (&tfdt->header, buffer, size, offset)) {
4386     return 0;
4387   }
4388
4389   /* 32-bit time if version == 0 else 64-bit: */
4390   if (tfdt->header.version == 0)
4391     prop_copy_uint32 (tfdt->base_media_decode_time, buffer, size, offset);
4392   else
4393     prop_copy_uint64 (tfdt->base_media_decode_time, buffer, size, offset);
4394
4395   atom_write_size (buffer, size, offset, original_offset);
4396   return *offset - original_offset;
4397 }
4398
4399 static guint64
4400 atom_trun_copy_data (AtomTRUN * trun, guint8 ** buffer, guint64 * size,
4401     guint64 * offset, guint32 * data_offset)
4402 {
4403   guint64 original_offset = *offset;
4404   guint32 flags, i;
4405
4406   flags = atom_full_get_flags_as_uint (&trun->header);
4407
4408   /* if first trun in moof, forcibly add data_offset and record
4409    * where it must be written later on */
4410   if (data_offset && !*data_offset) {
4411     flags |= TR_DATA_OFFSET;
4412   } else {
4413     flags &= ~TR_DATA_OFFSET;
4414   }
4415
4416   atom_full_set_flags_as_uint (&trun->header, flags);
4417
4418   if (!atom_full_copy_data (&trun->header, buffer, size, offset)) {
4419     return 0;
4420   }
4421
4422   prop_copy_uint32 (trun->sample_count, buffer, size, offset);
4423
4424   if (flags & TR_DATA_OFFSET) {
4425     *data_offset = *offset;
4426     prop_copy_int32 (trun->data_offset, buffer, size, offset);
4427   }
4428   if (flags & TR_FIRST_SAMPLE_FLAGS)
4429     prop_copy_uint32 (trun->first_sample_flags, buffer, size, offset);
4430
4431   for (i = 0; i < atom_array_get_len (&trun->entries); i++) {
4432     TRUNSampleEntry *entry = &atom_array_index (&trun->entries, i);
4433
4434     if (flags & TR_SAMPLE_DURATION)
4435       prop_copy_uint32 (entry->sample_duration, buffer, size, offset);
4436     if (flags & TR_SAMPLE_SIZE)
4437       prop_copy_uint32 (entry->sample_size, buffer, size, offset);
4438     if (flags & TR_SAMPLE_FLAGS)
4439       prop_copy_uint32 (entry->sample_flags, buffer, size, offset);
4440     if (flags & TR_COMPOSITION_TIME_OFFSETS)
4441       prop_copy_uint32 (entry->sample_composition_time_offset,
4442           buffer, size, offset);
4443   }
4444
4445   atom_write_size (buffer, size, offset, original_offset);
4446   return *offset - original_offset;
4447 }
4448
4449 static guint64
4450 atom_sdtp_copy_data (AtomSDTP * sdtp, guint8 ** buffer, guint64 * size,
4451     guint64 * offset)
4452 {
4453   guint64 original_offset = *offset;
4454
4455   if (!atom_full_copy_data (&sdtp->header, buffer, size, offset)) {
4456     return 0;
4457   }
4458
4459   /* all entries at once */
4460   prop_copy_fixed_size_string (&atom_array_index (&sdtp->entries, 0),
4461       atom_array_get_len (&sdtp->entries), buffer, size, offset);
4462
4463   atom_write_size (buffer, size, offset, original_offset);
4464   return *offset - original_offset;
4465 }
4466
4467 static guint64
4468 atom_traf_copy_data (AtomTRAF * traf, guint8 ** buffer, guint64 * size,
4469     guint64 * offset, guint32 * data_offset)
4470 {
4471   guint64 original_offset = *offset;
4472   GList *walker;
4473
4474   if (!atom_copy_data (&traf->header, buffer, size, offset)) {
4475     return 0;
4476   }
4477   if (!atom_tfhd_copy_data (&traf->tfhd, buffer, size, offset)) {
4478     return 0;
4479   }
4480   if (!atom_tfdt_copy_data (&traf->tfdt, buffer, size, offset)) {
4481     return 0;
4482   }
4483
4484   walker = g_list_first (traf->truns);
4485   while (walker != NULL) {
4486     if (!atom_trun_copy_data ((AtomTRUN *) walker->data, buffer, size, offset,
4487             data_offset)) {
4488       return 0;
4489     }
4490     walker = g_list_next (walker);
4491   }
4492
4493   walker = g_list_first (traf->sdtps);
4494   while (walker != NULL) {
4495     if (!atom_sdtp_copy_data ((AtomSDTP *) walker->data, buffer, size, offset)) {
4496       return 0;
4497     }
4498     walker = g_list_next (walker);
4499   }
4500
4501   atom_write_size (buffer, size, offset, original_offset);
4502   return *offset - original_offset;
4503 }
4504
4505 /* creates moof atom; metadata is written expecting actual buffer data
4506  * is in mdata directly after moof, and is consecutively written per trak */
4507 guint64
4508 atom_moof_copy_data (AtomMOOF * moof, guint8 ** buffer,
4509     guint64 * size, guint64 * offset)
4510 {
4511   guint64 original_offset = *offset;
4512   GList *walker;
4513   guint32 data_offset = 0;
4514
4515   if (!atom_copy_data (&moof->header, buffer, size, offset))
4516     return 0;
4517
4518   if (!atom_mfhd_copy_data (&moof->mfhd, buffer, size, offset))
4519     return 0;
4520
4521   walker = g_list_first (moof->trafs);
4522   while (walker != NULL) {
4523     if (!atom_traf_copy_data ((AtomTRAF *) walker->data, buffer, size, offset,
4524             &data_offset)) {
4525       return 0;
4526     }
4527     walker = g_list_next (walker);
4528   }
4529
4530   atom_write_size (buffer, size, offset, original_offset);
4531
4532   if (*buffer && data_offset) {
4533     /* first trun needs a data-offset relative to moof start
4534      *   = moof size + mdat prefix */
4535     GST_WRITE_UINT32_BE (*buffer + data_offset, *offset - original_offset + 8);
4536   }
4537
4538   return *offset - original_offset;
4539 }
4540
4541 static void
4542 atom_tfhd_init (AtomTFHD * tfhd, guint32 track_ID)
4543 {
4544   guint8 flags[3] = { 0, 0, 0 };
4545
4546   atom_full_init (&tfhd->header, FOURCC_tfhd, 0, 0, 0, flags);
4547   tfhd->track_ID = track_ID;
4548   tfhd->base_data_offset = 0;
4549   tfhd->sample_description_index = 1;
4550   tfhd->default_sample_duration = 0;
4551   tfhd->default_sample_size = 0;
4552   tfhd->default_sample_flags = 0;
4553 }
4554
4555 static void
4556 atom_tfdt_init (AtomTFDT * tfdt)
4557 {
4558   guint8 flags[3] = { 0, 0, 0 };
4559   atom_full_init (&tfdt->header, FOURCC_tfdt, 0, 0, 0, flags);
4560
4561   tfdt->base_media_decode_time = 0;
4562 }
4563
4564 static void
4565 atom_trun_init (AtomTRUN * trun)
4566 {
4567   guint8 flags[3] = { 0, 0, 0 };
4568
4569   atom_full_init (&trun->header, FOURCC_trun, 0, 0, 0, flags);
4570   trun->sample_count = 0;
4571   trun->data_offset = 0;
4572   trun->first_sample_flags = 0;
4573   atom_array_init (&trun->entries, 512);
4574 }
4575
4576 static AtomTRUN *
4577 atom_trun_new (void)
4578 {
4579   AtomTRUN *trun = g_new0 (AtomTRUN, 1);
4580
4581   atom_trun_init (trun);
4582   return trun;
4583 }
4584
4585 static void
4586 atom_sdtp_init (AtomSDTP * sdtp)
4587 {
4588   guint8 flags[3] = { 0, 0, 0 };
4589
4590   atom_full_init (&sdtp->header, FOURCC_sdtp, 0, 0, 0, flags);
4591   atom_array_init (&sdtp->entries, 512);
4592 }
4593
4594 static AtomSDTP *
4595 atom_sdtp_new (AtomsContext * context)
4596 {
4597   AtomSDTP *sdtp = g_new0 (AtomSDTP, 1);
4598
4599   atom_sdtp_init (sdtp);
4600   return sdtp;
4601 }
4602
4603 static void
4604 atom_traf_add_sdtp (AtomTRAF * traf, AtomSDTP * sdtp)
4605 {
4606   traf->sdtps = g_list_append (traf->sdtps, sdtp);
4607 }
4608
4609 static void
4610 atom_sdtp_add_samples (AtomSDTP * sdtp, guint8 val)
4611 {
4612   /* it does not make much/any sense according to specs,
4613    * but that's how MS isml samples seem to do it */
4614   atom_array_append (&sdtp->entries, val, 256);
4615 }
4616
4617 static void
4618 atom_trun_add_samples (AtomTRUN * trun, guint32 delta, guint32 size,
4619     guint32 flags, gint64 pts_offset)
4620 {
4621   TRUNSampleEntry nentry;
4622
4623   if (pts_offset != 0)
4624     trun->header.flags[1] |= (TR_COMPOSITION_TIME_OFFSETS >> 8);
4625
4626   nentry.sample_duration = delta;
4627   nentry.sample_size = size;
4628   nentry.sample_flags = flags;
4629   nentry.sample_composition_time_offset = pts_offset;
4630   atom_array_append (&trun->entries, nentry, 256);
4631   trun->sample_count++;
4632 }
4633
4634 static void
4635 atom_traf_init (AtomTRAF * traf, AtomsContext * context, guint32 track_ID)
4636 {
4637   atom_header_set (&traf->header, FOURCC_traf, 0, 0);
4638   atom_tfdt_init (&traf->tfdt);
4639   atom_tfhd_init (&traf->tfhd, track_ID);
4640   traf->truns = NULL;
4641
4642   if (context->flavor == ATOMS_TREE_FLAVOR_ISML)
4643     atom_traf_add_sdtp (traf, atom_sdtp_new (context));
4644 }
4645
4646 AtomTRAF *
4647 atom_traf_new (AtomsContext * context, guint32 track_ID)
4648 {
4649   AtomTRAF *traf = g_new0 (AtomTRAF, 1);
4650
4651   atom_traf_init (traf, context, track_ID);
4652   return traf;
4653 }
4654
4655 void
4656 atom_traf_set_base_decode_time (AtomTRAF * traf, guint64 base_decode_time)
4657 {
4658   traf->tfdt.base_media_decode_time = base_decode_time;
4659   /* If we need to write a 64-bit tfdt, set the atom version */
4660   if (base_decode_time > G_MAXUINT32)
4661     traf->tfdt.header.version = 1;
4662 }
4663
4664 static void
4665 atom_traf_add_trun (AtomTRAF * traf, AtomTRUN * trun)
4666 {
4667   traf->truns = g_list_append (traf->truns, trun);
4668 }
4669
4670 void
4671 atom_traf_add_samples (AtomTRAF * traf, guint32 delta, guint32 size,
4672     gboolean sync, gint64 pts_offset, gboolean sdtp_sync)
4673 {
4674   AtomTRUN *trun;
4675   guint32 flags;
4676
4677   /* 0x10000 is sample-is-difference-sample flag
4678    * low byte stuff is what ismv uses */
4679   flags = (sync ? 0x0 : 0x10000) | (sdtp_sync ? 0x40 : 0xc0);
4680
4681   if (G_UNLIKELY (!traf->truns)) {
4682     trun = atom_trun_new ();
4683     atom_traf_add_trun (traf, trun);
4684     /* optimistic; indicate all defaults present in tfhd */
4685     traf->tfhd.header.flags[2] = TF_DEFAULT_SAMPLE_DURATION |
4686         TF_DEFAULT_SAMPLE_SIZE | TF_DEFAULT_SAMPLE_FLAGS;
4687     traf->tfhd.default_sample_duration = delta;
4688     traf->tfhd.default_sample_size = size;
4689     traf->tfhd.default_sample_flags = flags;
4690     trun->first_sample_flags = flags;
4691   }
4692
4693   trun = traf->truns->data;
4694
4695   /* check if still matching defaults,
4696    * if not, abandon default and need entry for each sample */
4697   if (traf->tfhd.default_sample_duration != delta) {
4698     traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_DURATION;
4699     trun->header.flags[1] |= (TR_SAMPLE_DURATION >> 8);
4700   }
4701   if (traf->tfhd.default_sample_size != size) {
4702     traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_SIZE;
4703     trun->header.flags[1] |= (TR_SAMPLE_SIZE >> 8);
4704   }
4705   if (traf->tfhd.default_sample_flags != flags) {
4706     if (trun->sample_count == 1) {
4707       /* at least will need first sample flag */
4708       traf->tfhd.default_sample_flags = flags;
4709       trun->header.flags[2] |= TR_FIRST_SAMPLE_FLAGS;
4710     } else {
4711       /* now we need sample flags for each sample */
4712       traf->tfhd.header.flags[2] &= ~TF_DEFAULT_SAMPLE_FLAGS;
4713       trun->header.flags[1] |= (TR_SAMPLE_FLAGS >> 8);
4714       trun->header.flags[2] &= ~TR_FIRST_SAMPLE_FLAGS;
4715     }
4716   }
4717
4718   atom_trun_add_samples (traf->truns->data, delta, size, flags, pts_offset);
4719
4720   if (traf->sdtps)
4721     atom_sdtp_add_samples (traf->sdtps->data, 0x10 | ((flags & 0xff) >> 4));
4722 }
4723
4724 guint32
4725 atom_traf_get_sample_num (AtomTRAF * traf)
4726 {
4727   AtomTRUN *trun;
4728
4729   if (G_UNLIKELY (!traf->truns))
4730     return 0;
4731
4732   trun = traf->truns->data;
4733   return atom_array_get_len (&trun->entries);
4734 }
4735
4736 void
4737 atom_moof_add_traf (AtomMOOF * moof, AtomTRAF * traf)
4738 {
4739   moof->trafs = g_list_append (moof->trafs, traf);
4740 }
4741
4742 static void
4743 atom_tfra_free (AtomTFRA * tfra)
4744 {
4745   atom_full_clear (&tfra->header);
4746   atom_array_clear (&tfra->entries);
4747   g_free (tfra);
4748 }
4749
4750 AtomMFRA *
4751 atom_mfra_new (AtomsContext * context)
4752 {
4753   AtomMFRA *mfra = g_new0 (AtomMFRA, 1);
4754
4755   atom_header_set (&mfra->header, FOURCC_mfra, 0, 0);
4756   return mfra;
4757 }
4758
4759 void
4760 atom_mfra_add_tfra (AtomMFRA * mfra, AtomTFRA * tfra)
4761 {
4762   mfra->tfras = g_list_append (mfra->tfras, tfra);
4763 }
4764
4765 void
4766 atom_mfra_free (AtomMFRA * mfra)
4767 {
4768   GList *walker;
4769
4770   walker = mfra->tfras;
4771   while (walker) {
4772     atom_tfra_free ((AtomTFRA *) walker->data);
4773     walker = g_list_next (walker);
4774   }
4775   g_list_free (mfra->tfras);
4776   mfra->tfras = NULL;
4777
4778   atom_clear (&mfra->header);
4779   g_free (mfra);
4780 }
4781
4782 static void
4783 atom_tfra_init (AtomTFRA * tfra, guint32 track_ID)
4784 {
4785   guint8 flags[3] = { 0, 0, 0 };
4786
4787   atom_full_init (&tfra->header, FOURCC_tfra, 0, 0, 0, flags);
4788   tfra->track_ID = track_ID;
4789   atom_array_init (&tfra->entries, 512);
4790 }
4791
4792 AtomTFRA *
4793 atom_tfra_new (AtomsContext * context, guint32 track_ID)
4794 {
4795   AtomTFRA *tfra = g_new0 (AtomTFRA, 1);
4796
4797   atom_tfra_init (tfra, track_ID);
4798   return tfra;
4799
4800 }
4801
4802 static inline gint
4803 need_bytes (guint32 num)
4804 {
4805   gint n = 0;
4806
4807   while (num >>= 8)
4808     n++;
4809
4810   return n;
4811 }
4812
4813 void
4814 atom_tfra_add_entry (AtomTFRA * tfra, guint64 dts, guint32 sample_num)
4815 {
4816   TFRAEntry entry;
4817
4818   entry.time = dts;
4819   /* fill in later */
4820   entry.moof_offset = 0;
4821   /* always write a single trun in a single traf */
4822   entry.traf_number = 1;
4823   entry.trun_number = 1;
4824   entry.sample_number = sample_num;
4825
4826   /* auto-use 64 bits if needed */
4827   if (dts > G_MAXUINT32)
4828     tfra->header.version = 1;
4829
4830   /* 1 byte will always do for traf and trun number,
4831    * check how much sample_num needs */
4832   tfra->lengths = (tfra->lengths & 0xfc) ||
4833       MAX (tfra->lengths, need_bytes (sample_num));
4834
4835   atom_array_append (&tfra->entries, entry, 256);
4836 }
4837
4838 void
4839 atom_tfra_update_offset (AtomTFRA * tfra, guint64 offset)
4840 {
4841   gint i;
4842
4843   /* auto-use 64 bits if needed */
4844   if (offset > G_MAXUINT32)
4845     tfra->header.version = 1;
4846
4847   for (i = atom_array_get_len (&tfra->entries) - 1; i >= 0; i--) {
4848     TFRAEntry *entry = &atom_array_index (&tfra->entries, i);
4849
4850     if (entry->moof_offset)
4851       break;
4852     entry->moof_offset = offset;
4853   }
4854 }
4855
4856 static guint64
4857 atom_tfra_copy_data (AtomTFRA * tfra, guint8 ** buffer, guint64 * size,
4858     guint64 * offset)
4859 {
4860   guint64 original_offset = *offset;
4861   guint32 i;
4862   TFRAEntry *entry;
4863   guint32 data;
4864   guint bytes;
4865   guint version;
4866
4867   if (!atom_full_copy_data (&tfra->header, buffer, size, offset)) {
4868     return 0;
4869   }
4870
4871   prop_copy_uint32 (tfra->track_ID, buffer, size, offset);
4872   prop_copy_uint32 (tfra->lengths, buffer, size, offset);
4873   prop_copy_uint32 (atom_array_get_len (&tfra->entries), buffer, size, offset);
4874
4875   version = tfra->header.version;
4876   for (i = 0; i < atom_array_get_len (&tfra->entries); ++i) {
4877     entry = &atom_array_index (&tfra->entries, i);
4878     if (version) {
4879       prop_copy_uint64 (entry->time, buffer, size, offset);
4880       prop_copy_uint64 (entry->moof_offset, buffer, size, offset);
4881     } else {
4882       prop_copy_uint32 (entry->time, buffer, size, offset);
4883       prop_copy_uint32 (entry->moof_offset, buffer, size, offset);
4884     }
4885
4886     bytes = (tfra->lengths & (0x3 << 4)) + 1;
4887     data = GUINT32_TO_BE (entry->traf_number);
4888     prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
4889         buffer, size, offset);
4890
4891     bytes = (tfra->lengths & (0x3 << 2)) + 1;
4892     data = GUINT32_TO_BE (entry->trun_number);
4893     prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
4894         buffer, size, offset);
4895
4896     bytes = (tfra->lengths & (0x3)) + 1;
4897     data = GUINT32_TO_BE (entry->sample_number);
4898     prop_copy_fixed_size_string (((guint8 *) & data) + 4 - bytes, bytes,
4899         buffer, size, offset);
4900
4901   }
4902
4903   atom_write_size (buffer, size, offset, original_offset);
4904   return *offset - original_offset;
4905 }
4906
4907 static guint64
4908 atom_mfro_copy_data (guint32 s, guint8 ** buffer, guint64 * size,
4909     guint64 * offset)
4910 {
4911   guint64 original_offset = *offset;
4912   guint8 flags[3] = { 0, 0, 0 };
4913   AtomFull mfro;
4914
4915   atom_full_init (&mfro, FOURCC_mfro, 0, 0, 0, flags);
4916
4917   if (!atom_full_copy_data (&mfro, buffer, size, offset)) {
4918     return 0;
4919   }
4920
4921   prop_copy_uint32 (s, buffer, size, offset);
4922
4923   atom_write_size (buffer, size, offset, original_offset);
4924
4925   return *offset - original_offset;
4926 }
4927
4928
4929 guint64
4930 atom_mfra_copy_data (AtomMFRA * mfra, guint8 ** buffer, guint64 * size,
4931     guint64 * offset)
4932 {
4933   guint64 original_offset = *offset;
4934   GList *walker;
4935
4936   if (!atom_copy_data (&mfra->header, buffer, size, offset))
4937     return 0;
4938
4939   walker = g_list_first (mfra->tfras);
4940   while (walker != NULL) {
4941     if (!atom_tfra_copy_data ((AtomTFRA *) walker->data, buffer, size, offset)) {
4942       return 0;
4943     }
4944     walker = g_list_next (walker);
4945   }
4946
4947   /* 16 is the size of the mfro atom */
4948   if (!atom_mfro_copy_data (*offset - original_offset + 16, buffer,
4949           size, offset))
4950     return 0;
4951
4952   atom_write_size (buffer, size, offset, original_offset);
4953   return *offset - original_offset;
4954 }
4955
4956 /* some sample description construction helpers */
4957
4958 AtomInfo *
4959 build_esds_extension (AtomTRAK * trak, guint8 object_type, guint8 stream_type,
4960     const GstBuffer * codec_data, guint32 avg_bitrate, guint32 max_bitrate)
4961 {
4962   guint32 track_id;
4963   AtomESDS *esds;
4964
4965   track_id = trak->tkhd.track_ID;
4966
4967   esds = atom_esds_new ();
4968   esds->es.id = track_id & 0xFFFF;
4969   esds->es.dec_conf_desc.object_type = object_type;
4970   esds->es.dec_conf_desc.stream_type = stream_type << 2 | 0x01;
4971
4972   if (avg_bitrate > 0)
4973     esds->es.dec_conf_desc.avg_bitrate = avg_bitrate;
4974   if (max_bitrate > 0)
4975     esds->es.dec_conf_desc.max_bitrate = max_bitrate;
4976
4977   /* optional DecoderSpecificInfo */
4978   if (codec_data) {
4979     DecoderSpecificInfoDescriptor *desc;
4980     gsize size;
4981
4982     esds->es.dec_conf_desc.dec_specific_info = desc =
4983         desc_dec_specific_info_new ();
4984     size = gst_buffer_get_size ((GstBuffer *) codec_data);
4985     desc_dec_specific_info_alloc_data (desc, size);
4986     gst_buffer_extract ((GstBuffer *) codec_data, 0, desc->data, size);
4987   }
4988
4989   return build_atom_info_wrapper ((Atom *) esds, atom_esds_copy_data,
4990       atom_esds_free);
4991 }
4992
4993 AtomInfo *
4994 build_btrt_extension (guint32 buffer_size_db, guint32 avg_bitrate,
4995     guint32 max_bitrate)
4996 {
4997   AtomData *atom_data = atom_data_new (FOURCC_btrt);
4998   guint8 *data;
4999
5000   atom_data_alloc_mem (atom_data, 12);
5001   data = atom_data->data;
5002
5003   GST_WRITE_UINT32_BE (data, buffer_size_db);
5004   GST_WRITE_UINT32_BE (data + 4, max_bitrate);
5005   GST_WRITE_UINT32_BE (data + 8, avg_bitrate);
5006
5007   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
5008       atom_data_free);
5009 }
5010
5011 static AtomInfo *
5012 build_mov_wave_extension (guint32 fourcc, AtomInfo * atom1, AtomInfo * atom2,
5013     gboolean terminator)
5014 {
5015   AtomWAVE *wave;
5016   AtomFRMA *frma;
5017   Atom *ext_atom;
5018
5019   /* Build WAVE atom for sample table entry */
5020   wave = atom_wave_new ();
5021
5022   /* Prepend Terminator atom to the WAVE list first, so it ends up last */
5023   if (terminator) {
5024     ext_atom = (Atom *) atom_data_new (FOURCC_null);
5025     wave->extension_atoms =
5026         atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
5027         (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
5028   }
5029
5030   /* Add supplied atoms to WAVE */
5031   if (atom2)
5032     wave->extension_atoms = g_list_prepend (wave->extension_atoms, atom2);
5033   if (atom1)
5034     wave->extension_atoms = g_list_prepend (wave->extension_atoms, atom1);
5035
5036   /* Add FRMA to the WAVE */
5037   frma = atom_frma_new ();
5038   frma->media_type = fourcc;
5039
5040   wave->extension_atoms =
5041       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
5042       (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
5043
5044   return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
5045       atom_wave_free);
5046 }
5047
5048 AtomInfo *
5049 build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data,
5050     guint32 avg_bitrate, guint32 max_bitrate)
5051 {
5052   AtomInfo *esds, *mp4a;
5053   GstBuffer *buf;
5054   guint32 tmp = 0;
5055
5056   /* Add ESDS atom to WAVE */
5057   esds = build_esds_extension (trak, ESDS_OBJECT_TYPE_MPEG4_P3,
5058       ESDS_STREAM_TYPE_AUDIO, codec_data, avg_bitrate, max_bitrate);
5059
5060   /* Add MP4A atom to the WAVE:
5061    * not really in spec, but makes offset based players happy */
5062   buf = GST_BUFFER_NEW_READONLY (&tmp, 4);
5063   mp4a = build_codec_data_extension (FOURCC_mp4a, buf);
5064   gst_buffer_unref (buf);
5065
5066   return build_mov_wave_extension (FOURCC_mp4a, mp4a, esds, TRUE);
5067 }
5068
5069 AtomInfo *
5070 build_mov_alac_extension (const GstBuffer * codec_data)
5071 {
5072   AtomInfo *alac;
5073
5074   alac = build_codec_data_extension (FOURCC_alac, codec_data);
5075
5076   return build_mov_wave_extension (FOURCC_alac, NULL, alac, TRUE);
5077 }
5078
5079 AtomInfo *
5080 build_jp2x_extension (const GstBuffer * prefix)
5081 {
5082   AtomData *atom_data;
5083
5084   if (!prefix) {
5085     return NULL;
5086   }
5087
5088   atom_data = atom_data_new_from_gst_buffer (FOURCC_jp2x, prefix);
5089
5090   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
5091       atom_data_free);
5092 }
5093
5094 AtomInfo *
5095 build_jp2h_extension (gint width, gint height, const gchar * colorspace,
5096     gint ncomp, const GValue * cmap_array, const GValue * cdef_array)
5097 {
5098   AtomData *atom_data;
5099   GstBuffer *buf;
5100   guint8 cenum;
5101   gint i;
5102   gint idhr_size = 22;
5103   gint colr_size = 15;
5104   gint cmap_size = 0, cdef_size = 0;
5105   gint cmap_array_size = 0;
5106   gint cdef_array_size = 0;
5107   GstByteWriter writer;
5108
5109   g_return_val_if_fail (cmap_array == NULL ||
5110       GST_VALUE_HOLDS_ARRAY (cmap_array), NULL);
5111   g_return_val_if_fail (cdef_array == NULL ||
5112       GST_VALUE_HOLDS_ARRAY (cdef_array), NULL);
5113
5114   if (g_str_equal (colorspace, "sRGB")) {
5115     cenum = 0x10;
5116     if (ncomp == 0)
5117       ncomp = 3;
5118   } else if (g_str_equal (colorspace, "GRAY")) {
5119     cenum = 0x11;
5120     if (ncomp == 0)
5121       ncomp = 1;
5122   } else if (g_str_equal (colorspace, "sYUV")) {
5123     cenum = 0x12;
5124     if (ncomp == 0)
5125       ncomp = 3;
5126   } else
5127     return NULL;
5128
5129   if (cmap_array) {
5130     cmap_array_size = gst_value_array_get_size (cmap_array);
5131     cmap_size = 8 + cmap_array_size * 4;
5132   }
5133   if (cdef_array) {
5134     cdef_array_size = gst_value_array_get_size (cdef_array);
5135     cdef_size = 8 + 2 + cdef_array_size * 6;
5136   }
5137
5138   gst_byte_writer_init_with_size (&writer,
5139       idhr_size + colr_size + cmap_size + cdef_size, TRUE);
5140
5141   /* ihdr = image header box */
5142   gst_byte_writer_put_uint32_be_unchecked (&writer, 22);
5143   gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_ihdr);
5144   gst_byte_writer_put_uint32_be_unchecked (&writer, height);
5145   gst_byte_writer_put_uint32_be_unchecked (&writer, width);
5146   gst_byte_writer_put_uint16_be_unchecked (&writer, ncomp);
5147   /* 8 bits per component, unsigned */
5148   gst_byte_writer_put_uint8_unchecked (&writer, 0x7);
5149   /* compression type; reserved */
5150   gst_byte_writer_put_uint8_unchecked (&writer, 0x7);
5151   /* colour space (un)known */
5152   gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
5153   /* intellectual property right (box present) */
5154   gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
5155
5156   /* colour specification box */
5157   gst_byte_writer_put_uint32_be_unchecked (&writer, 15);
5158   gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_colr);
5159
5160   /* specification method: enumerated */
5161   gst_byte_writer_put_uint8_unchecked (&writer, 0x1);
5162   /* precedence; reserved */
5163   gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
5164   /* approximation; reserved */
5165   gst_byte_writer_put_uint8_unchecked (&writer, 0x0);
5166   /* enumerated colourspace */
5167   gst_byte_writer_put_uint32_be_unchecked (&writer, cenum);
5168
5169   if (cmap_array) {
5170     gst_byte_writer_put_uint32_be_unchecked (&writer, cmap_size);
5171     gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_cmap);
5172     for (i = 0; i < cmap_array_size; i++) {
5173       const GValue *item;
5174       gint value;
5175       guint16 cmp;
5176       guint8 mtyp;
5177       guint8 pcol;
5178       item = gst_value_array_get_value (cmap_array, i);
5179       value = g_value_get_int (item);
5180
5181       /* value is '(mtyp << 24) | (pcol << 16) | cmp' */
5182       cmp = value & 0xFFFF;
5183       mtyp = value >> 24;
5184       pcol = (value >> 16) & 0xFF;
5185
5186       if (mtyp == 1)
5187         GST_WARNING ("MTYP of cmap atom signals Pallete Mapping, but we don't "
5188             "handle Pallete mapping atoms yet");
5189
5190       gst_byte_writer_put_uint16_be_unchecked (&writer, cmp);
5191       gst_byte_writer_put_uint8_unchecked (&writer, mtyp);
5192       gst_byte_writer_put_uint8_unchecked (&writer, pcol);
5193     }
5194   }
5195
5196   if (cdef_array) {
5197     gst_byte_writer_put_uint32_be_unchecked (&writer, cdef_size);
5198     gst_byte_writer_put_uint32_le_unchecked (&writer, FOURCC_cdef);
5199     gst_byte_writer_put_uint16_be_unchecked (&writer, cdef_array_size);
5200     for (i = 0; i < cdef_array_size; i++) {
5201       const GValue *item;
5202       gint value;
5203       item = gst_value_array_get_value (cdef_array, i);
5204       value = g_value_get_int (item);
5205
5206       gst_byte_writer_put_uint16_be_unchecked (&writer, i);
5207       if (value > 0) {
5208         gst_byte_writer_put_uint16_be_unchecked (&writer, 0);
5209         gst_byte_writer_put_uint16_be_unchecked (&writer, value);
5210       } else if (value < 0) {
5211         gst_byte_writer_put_uint16_be_unchecked (&writer, -value);
5212         gst_byte_writer_put_uint16_be_unchecked (&writer, 0);   /* TODO what here? */
5213       } else {
5214         gst_byte_writer_put_uint16_be_unchecked (&writer, 1);
5215         gst_byte_writer_put_uint16_be_unchecked (&writer, 0);
5216       }
5217     }
5218   }
5219
5220   g_assert (gst_byte_writer_get_remaining (&writer) == 0);
5221   buf = gst_byte_writer_reset_and_get_buffer (&writer);
5222
5223   atom_data = atom_data_new_from_gst_buffer (FOURCC_jp2h, buf);
5224   gst_buffer_unref (buf);
5225
5226   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
5227       atom_data_free);
5228 }
5229
5230 AtomInfo *
5231 build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data)
5232 {
5233   AtomData *data;
5234   AtomInfo *result = NULL;
5235
5236   if (codec_data) {
5237     data = atom_data_new_from_gst_buffer (fourcc, codec_data);
5238     result = build_atom_info_wrapper ((Atom *) data, atom_data_copy_data,
5239         atom_data_free);
5240   }
5241
5242   return result;
5243 }
5244
5245 AtomInfo *
5246 build_amr_extension (void)
5247 {
5248   guint8 ext[9];
5249   GstBuffer *buf;
5250   AtomInfo *res;
5251
5252   /* vendor */
5253   GST_WRITE_UINT32_LE (ext, 0);
5254   /* decoder version */
5255   GST_WRITE_UINT8 (ext + 4, 0);
5256   /* mode set (all modes) */
5257   GST_WRITE_UINT16_BE (ext + 5, 0x81FF);
5258   /* mode change period (no restriction) */
5259   GST_WRITE_UINT8 (ext + 7, 0);
5260   /* frames per sample */
5261   GST_WRITE_UINT8 (ext + 8, 1);
5262
5263   buf = GST_BUFFER_NEW_READONLY (ext, sizeof (ext));
5264   res = build_codec_data_extension (FOURCC_damr, buf);
5265   gst_buffer_unref (buf);
5266   return res;
5267 }
5268
5269 AtomInfo *
5270 build_h263_extension (void)
5271 {
5272   guint8 ext[7];
5273   GstBuffer *buf;
5274   AtomInfo *res;
5275
5276   /* vendor */
5277   GST_WRITE_UINT32_LE (ext, 0);
5278   /* decoder version */
5279   GST_WRITE_UINT8 (ext + 4, 0);
5280   /* level / profile */
5281   /* FIXME ? maybe ? obtain somewhere; baseline for now */
5282   GST_WRITE_UINT8 (ext + 5, 10);
5283   GST_WRITE_UINT8 (ext + 6, 0);
5284
5285   buf = GST_BUFFER_NEW_READONLY (ext, sizeof (ext));
5286   res = build_codec_data_extension (FOURCC_d263, buf);
5287   gst_buffer_unref (buf);
5288   return res;
5289 }
5290
5291 AtomInfo *
5292 build_gama_atom (gdouble gamma)
5293 {
5294   AtomInfo *res;
5295   guint32 gamma_fp;
5296   GstBuffer *buf;
5297
5298   /* convert to uint32 from fixed point */
5299   gamma_fp = (guint32) 65536 *gamma;
5300
5301   gamma_fp = GUINT32_TO_BE (gamma_fp);
5302   buf = GST_BUFFER_NEW_READONLY (&gamma_fp, 4);
5303   res = build_codec_data_extension (FOURCC_gama, buf);
5304   gst_buffer_unref (buf);
5305   return res;
5306 }
5307
5308 AtomInfo *
5309 build_SMI_atom (const GstBuffer * seqh)
5310 {
5311   AtomInfo *res;
5312   GstBuffer *buf;
5313   gsize size;
5314   guint8 *data;
5315
5316   /* the seqh plus its size and fourcc */
5317   size = gst_buffer_get_size ((GstBuffer *) seqh);
5318   data = g_malloc (size + 8);
5319
5320   GST_WRITE_UINT32_LE (data, FOURCC_SEQH);
5321   GST_WRITE_UINT32_BE (data + 4, size + 8);
5322   gst_buffer_extract ((GstBuffer *) seqh, 0, data + 8, size);
5323   buf = gst_buffer_new_wrapped (data, size + 8);
5324   res = build_codec_data_extension (FOURCC_SMI_, buf);
5325   gst_buffer_unref (buf);
5326   return res;
5327 }
5328
5329 static AtomInfo *
5330 build_ima_adpcm_atom (gint channels, gint rate, gint blocksize)
5331 {
5332 #define IMA_ADPCM_ATOM_SIZE 20
5333   AtomData *atom_data;
5334   guint8 *data;
5335   guint32 fourcc;
5336   gint samplesperblock;
5337   gint bytespersec;
5338
5339   /* The FOURCC for WAV codecs in QT is 'ms' followed by the 16 bit wave codec
5340      identifier. Note that the identifier here is big-endian, but when used
5341      within the WAVE header (below), it's little endian. */
5342   fourcc = MS_WAVE_FOURCC (0x11);
5343
5344   atom_data = atom_data_new (fourcc);
5345   atom_data_alloc_mem (atom_data, IMA_ADPCM_ATOM_SIZE);
5346   data = atom_data->data;
5347
5348   /* This atom's content is a WAVE header, including 2 bytes of extra data.
5349      Note that all of this is little-endian, unlike most stuff in qt. */
5350   /* 4 bytes header per channel (including 1 sample). Then 2 samples per byte
5351      for the rest. Simplifies to this. */
5352   samplesperblock = 2 * blocksize / channels - 7;
5353   bytespersec = rate * blocksize / samplesperblock;
5354   GST_WRITE_UINT16_LE (data, 0x11);
5355   GST_WRITE_UINT16_LE (data + 2, channels);
5356   GST_WRITE_UINT32_LE (data + 4, rate);
5357   GST_WRITE_UINT32_LE (data + 8, bytespersec);
5358   GST_WRITE_UINT16_LE (data + 12, blocksize);
5359   GST_WRITE_UINT16_LE (data + 14, 4);
5360   GST_WRITE_UINT16_LE (data + 16, 2);   /* Two extra bytes */
5361   GST_WRITE_UINT16_LE (data + 18, samplesperblock);
5362
5363   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
5364       atom_data_free);
5365 }
5366
5367 AtomInfo *
5368 build_ima_adpcm_extension (gint channels, gint rate, gint blocksize)
5369 {
5370   AtomWAVE *wave;
5371   AtomFRMA *frma;
5372   Atom *ext_atom;
5373
5374   /* Add WAVE atom */
5375   wave = atom_wave_new ();
5376
5377   /* Prepend Terminator atom to the WAVE list first, so it ends up last */
5378   ext_atom = (Atom *) atom_data_new (FOURCC_null);
5379   wave->extension_atoms =
5380       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
5381       (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
5382
5383   /* Add wave ima adpcm atom to WAVE */
5384   wave->extension_atoms = g_list_prepend (wave->extension_atoms,
5385       build_ima_adpcm_atom (channels, rate, blocksize));
5386
5387   /* Add FRMA to the WAVE */
5388   frma = atom_frma_new ();
5389   frma->media_type = MS_WAVE_FOURCC (0x11);
5390
5391   wave->extension_atoms =
5392       atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
5393       (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
5394
5395   return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
5396       atom_wave_free);
5397 }
5398
5399 AtomInfo *
5400 build_ac3_extension (guint8 fscod, guint8 bsid, guint8 bsmod, guint8 acmod,
5401     guint8 lfe_on, guint8 bitrate_code)
5402 {
5403   AtomData *atom_data = atom_data_new (FOURCC_dac3);
5404   guint8 *data;
5405
5406   atom_data_alloc_mem (atom_data, 3);
5407   data = atom_data->data;
5408
5409   /* Bits from the spec
5410    * fscod 2
5411    * bsid  5
5412    * bsmod 3
5413    * acmod 3
5414    * lfeon 1
5415    * bit_rate_code 5
5416    * reserved 5
5417    */
5418
5419   /* Some bit manipulation magic. Need bitwriter */
5420   data[0] = (fscod << 6) | (bsid << 1) | ((bsmod >> 2) & 1);
5421   data[1] =
5422       ((bsmod & 0x3) << 6) | (acmod << 3) | ((lfe_on & 1) << 2) | ((bitrate_code
5423           >> 3) & 0x3);
5424   data[2] = ((bitrate_code & 0x7) << 5);
5425
5426   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
5427       atom_data_free);
5428 }
5429
5430 AtomInfo *
5431 build_opus_extension (guint32 rate, guint8 channels, guint8 mapping_family,
5432     guint8 stream_count, guint8 coupled_count, guint8 channel_mapping[256],
5433     guint16 pre_skip, guint16 output_gain)
5434 {
5435   AtomData *atom_data;
5436   guint8 *data_block;
5437   GstByteWriter bw;
5438   gboolean hdl = TRUE;
5439   guint data_block_len;
5440
5441   gst_byte_writer_init (&bw);
5442   hdl &= gst_byte_writer_put_uint8 (&bw, 0x00); /* version number */
5443   hdl &= gst_byte_writer_put_uint8 (&bw, channels);
5444   hdl &= gst_byte_writer_put_uint16_le (&bw, pre_skip);
5445   hdl &= gst_byte_writer_put_uint32_le (&bw, rate);
5446   hdl &= gst_byte_writer_put_uint16_le (&bw, output_gain);
5447   hdl &= gst_byte_writer_put_uint8 (&bw, mapping_family);
5448   if (mapping_family > 0) {
5449     hdl &= gst_byte_writer_put_uint8 (&bw, stream_count);
5450     hdl &= gst_byte_writer_put_uint8 (&bw, coupled_count);
5451     hdl &= gst_byte_writer_put_data (&bw, channel_mapping, channels);
5452   }
5453
5454   if (!hdl) {
5455     GST_WARNING ("Error creating header");
5456     return NULL;
5457   }
5458
5459   data_block_len = gst_byte_writer_get_size (&bw);
5460   data_block = gst_byte_writer_reset_and_get_data (&bw);
5461   atom_data = atom_data_new_from_data (FOURCC_dops, data_block, data_block_len);
5462   g_free (data_block);
5463
5464   return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
5465       atom_data_free);
5466 }
5467
5468 AtomInfo *
5469 build_uuid_xmp_atom (GstBuffer * xmp_data)
5470 {
5471   AtomUUID *uuid;
5472   gsize size;
5473   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
5474     0x97, 0xA9, 0x42, 0xE8,
5475     0x9C, 0x71, 0x99, 0x94,
5476     0x91, 0xE3, 0xAF, 0xAC
5477   };
5478
5479   if (xmp_data == NULL)
5480     return NULL;
5481
5482   uuid = atom_uuid_new ();
5483   memcpy (uuid->uuid, xmp_uuid, 16);
5484
5485   size = gst_buffer_get_size (xmp_data);
5486   uuid->data = g_malloc (size);
5487   uuid->datalen = size;
5488   gst_buffer_extract (xmp_data, 0, uuid->data, size);
5489
5490   return build_atom_info_wrapper ((Atom *) uuid, atom_uuid_copy_data,
5491       atom_uuid_free);
5492 }