"Fossies" - the Fresh Open Source Software Archive

Member "gst-plugins-good-1.20.3/gst/isomp4/atoms.c" (15 Jun 2022, 149743 Bytes) of package /linux/misc/gst-plugins-good-1.20.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "atoms.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.18.6_vs_1.20.0.

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