Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / mxf / mxfmux.c
1 /* GStreamer
2  * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-mxfmux
22  *
23  * mxfmux muxes different streams into an MXF file.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch -v filesrc location=/path/to/audio ! decodebin2 ! queue ! mxfmux name=m ! filesink location=file.mxf   filesrc location=/path/to/video ! decodebin2 ! queue ! m. 
29  * ]| This pipeline muxes an audio and video file into a single MXF file.
30  * </refsect2>
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <math.h>
38 #include <string.h>
39
40 #include "mxfmux.h"
41
42 #ifdef HAVE_SYS_UTSNAME_H
43 #include <sys/utsname.h>
44 #endif
45
46 GST_DEBUG_CATEGORY_STATIC (mxfmux_debug);
47 #define GST_CAT_DEFAULT mxfmux_debug
48
49 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
50     GST_PAD_SRC,
51     GST_PAD_ALWAYS,
52     GST_STATIC_CAPS ("application/mxf")
53     );
54
55 enum
56 {
57   PROP_0
58 };
59
60 GST_BOILERPLATE (GstMXFMux, gst_mxf_mux, GstElement, GST_TYPE_ELEMENT);
61
62 static void gst_mxf_mux_finalize (GObject * object);
63 static void gst_mxf_mux_set_property (GObject * object,
64     guint prop_id, const GValue * value, GParamSpec * pspec);
65 static void gst_mxf_mux_get_property (GObject * object,
66     guint prop_id, GValue * value, GParamSpec * pspec);
67
68 static GstFlowReturn gst_mxf_mux_collected (GstCollectPads * pads,
69     gpointer user_data);
70
71 static gboolean gst_mxf_mux_handle_src_event (GstPad * pad, GstEvent * event);
72 static GstPad *gst_mxf_mux_request_new_pad (GstElement * element,
73     GstPadTemplate * templ, const gchar * name);
74 static void gst_mxf_mux_release_pad (GstElement * element, GstPad * pad);
75
76 static GstStateChangeReturn
77 gst_mxf_mux_change_state (GstElement * element, GstStateChange transition);
78
79 static void gst_mxf_mux_reset (GstMXFMux * mux);
80
81 static GstFlowReturn
82 gst_mxf_mux_push (GstMXFMux * mux, GstBuffer * buf)
83 {
84   guint size = GST_BUFFER_SIZE (buf);
85   GstFlowReturn ret;
86
87   gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
88   ret = gst_pad_push (mux->srcpad, buf);
89   mux->offset += size;
90
91   return ret;
92 }
93
94 static void
95 gst_mxf_mux_base_init (gpointer g_class)
96 {
97   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
98   const GstPadTemplate **p;
99
100   gst_element_class_add_static_pad_template (element_class, &src_templ);
101
102   p = mxf_essence_element_writer_get_pad_templates ();
103   while (p && *p) {
104     gst_element_class_add_pad_template (element_class,
105         (GstPadTemplate *) (GST_OBJECT (*p)));
106     p++;
107   }
108
109   gst_element_class_set_details_simple (element_class, "MXF muxer",
110       "Codec/Muxer",
111       "Muxes video/audio streams into a MXF stream",
112       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
113 }
114
115 static void
116 gst_mxf_mux_class_init (GstMXFMuxClass * klass)
117 {
118   GObjectClass *gobject_class;
119   GstElementClass *gstelement_class;
120
121   GST_DEBUG_CATEGORY_INIT (mxfmux_debug, "mxfmux", 0, "MXF muxer");
122
123   gobject_class = (GObjectClass *) klass;
124   gstelement_class = (GstElementClass *) klass;
125
126   gobject_class->finalize = gst_mxf_mux_finalize;
127   gobject_class->set_property = gst_mxf_mux_set_property;
128   gobject_class->get_property = gst_mxf_mux_get_property;
129
130   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_mxf_mux_change_state);
131   gstelement_class->request_new_pad =
132       GST_DEBUG_FUNCPTR (gst_mxf_mux_request_new_pad);
133   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_mxf_mux_release_pad);
134 }
135
136 static void
137 gst_mxf_mux_init (GstMXFMux * mux, GstMXFMuxClass * g_class)
138 {
139   GstCaps *caps;
140
141   mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
142   gst_pad_set_event_function (mux->srcpad, gst_mxf_mux_handle_src_event);
143   caps = gst_caps_new_simple ("application/mxf", NULL);
144   gst_pad_set_caps (mux->srcpad, caps);
145   gst_caps_unref (caps);
146   gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
147
148   mux->collect = gst_collect_pads_new ();
149   gst_collect_pads_set_function (mux->collect,
150       (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_mxf_mux_collected), mux);
151
152   gst_mxf_mux_reset (mux);
153 }
154
155 static void
156 gst_mxf_mux_finalize (GObject * object)
157 {
158   GstMXFMux *mux = GST_MXF_MUX (object);
159
160   gst_mxf_mux_reset (mux);
161
162   if (mux->metadata) {
163     g_hash_table_destroy (mux->metadata);
164     mux->metadata = NULL;
165     g_list_free (mux->metadata_list);
166     mux->metadata_list = NULL;
167   }
168
169   gst_object_unref (mux->collect);
170
171   G_OBJECT_CLASS (parent_class)->finalize (object);
172 }
173
174 static void
175 gst_mxf_mux_set_property (GObject * object,
176     guint prop_id, const GValue * value, GParamSpec * pspec)
177 {
178   //GstMXFMux *mux = GST_MXF_MUX (object);
179
180   switch (prop_id) {
181     default:
182       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
183       break;
184   }
185 }
186
187 static void
188 gst_mxf_mux_get_property (GObject * object,
189     guint prop_id, GValue * value, GParamSpec * pspec)
190 {
191   //GstMXFMux *mux = GST_MXF_MUX (object);
192
193   switch (prop_id) {
194     default:
195       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
196       break;
197   }
198 }
199
200 static void
201 gst_mxf_mux_reset (GstMXFMux * mux)
202 {
203   GSList *sl;
204
205   while ((sl = mux->collect->data) != NULL) {
206     GstMXFMuxPad *cpad = (GstMXFMuxPad *) sl->data;
207
208     g_object_unref (cpad->adapter);
209     g_free (cpad->mapping_data);
210
211     gst_collect_pads_remove_pad (mux->collect, cpad->collect.pad);
212   }
213
214   mux->state = GST_MXF_MUX_STATE_HEADER;
215   mux->n_pads = 0;
216
217   if (mux->metadata) {
218     g_hash_table_destroy (mux->metadata);
219     mux->preface = NULL;
220     g_list_free (mux->metadata_list);
221     mux->metadata_list = NULL;
222   }
223   mux->metadata = mxf_metadata_hash_table_new ();
224
225   mxf_partition_pack_reset (&mux->partition);
226   mxf_primer_pack_reset (&mux->primer);
227   memset (&mux->min_edit_rate, 0, sizeof (MXFFraction));
228   mux->last_gc_timestamp = 0;
229   mux->last_gc_position = 0;
230   mux->offset = 0;
231 }
232
233 static gboolean
234 gst_mxf_mux_handle_src_event (GstPad * pad, GstEvent * event)
235 {
236   GstEventType type;
237
238   type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
239
240   switch (type) {
241     case GST_EVENT_SEEK:
242       /* disable seeking for now */
243       return FALSE;
244     default:
245       break;
246   }
247
248   return gst_pad_event_default (pad, event);
249 }
250
251 static gboolean
252 gst_mxf_mux_handle_sink_event (GstPad * pad, GstEvent * event)
253 {
254   GstMXFMux *mux = GST_MXF_MUX (gst_pad_get_parent (pad));
255   gboolean ret = TRUE;
256
257   switch (GST_EVENT_TYPE (event)) {
258     case GST_EVENT_TAG:
259       /* TODO: do something with the tags */
260       break;
261     case GST_EVENT_NEWSEGMENT:
262       /* We don't support NEWSEGMENT events */
263       ret = FALSE;
264       gst_event_unref (event);
265       break;
266     default:
267       break;
268   }
269
270   /* now GstCollectPads can take care of the rest, e.g. EOS */
271   if (ret)
272     ret = mux->collect_event (pad, event);
273   gst_object_unref (mux);
274
275   return ret;
276 }
277
278 static gboolean
279 gst_mxf_mux_setcaps (GstPad * pad, GstCaps * caps)
280 {
281   GstMXFMux *mux = GST_MXF_MUX (gst_pad_get_parent (pad));
282   GstMXFMuxPad *cpad = (GstMXFMuxPad *) gst_pad_get_element_private (pad);
283   gboolean ret = TRUE;
284   MXFUUID d_instance_uid = { {0,} };
285   MXFMetadataFileDescriptor *old_descriptor = cpad->descriptor;
286   GList *l;
287
288   GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps);
289
290   if (old_descriptor) {
291     memcpy (&d_instance_uid, &MXF_METADATA_BASE (old_descriptor)->instance_uid,
292         16);
293     cpad->descriptor = NULL;
294     g_free (cpad->mapping_data);
295     cpad->mapping_data = NULL;
296   }
297
298   cpad->descriptor =
299       cpad->writer->get_descriptor (gst_pad_get_pad_template (pad), caps,
300       &cpad->write_func, &cpad->mapping_data);
301
302   if (!cpad->descriptor) {
303     GST_ERROR_OBJECT (mux,
304         "Couldn't get descriptor for pad '%s' with caps %" GST_PTR_FORMAT,
305         GST_PAD_NAME (pad), caps);
306     gst_object_unref (mux);
307     return FALSE;
308   }
309
310   if (mxf_uuid_is_zero (&d_instance_uid))
311     mxf_uuid_init (&d_instance_uid, mux->metadata);
312
313   memcpy (&MXF_METADATA_BASE (cpad->descriptor)->instance_uid, &d_instance_uid,
314       16);
315
316   if (old_descriptor) {
317     for (l = mux->metadata_list; l; l = l->next) {
318       MXFMetadataBase *tmp = l->data;
319
320       if (mxf_uuid_is_equal (&d_instance_uid, &tmp->instance_uid)) {
321         l->data = cpad->descriptor;
322         break;
323       }
324     }
325   } else {
326     mux->metadata_list = g_list_prepend (mux->metadata_list, cpad->descriptor);
327   }
328
329   g_hash_table_replace (mux->metadata,
330       &MXF_METADATA_BASE (cpad->descriptor)->instance_uid, cpad->descriptor);
331
332   if (old_descriptor) {
333     if (mux->preface && mux->preface->content_storage &&
334         mux->preface->content_storage->packages) {
335       guint i, j;
336
337       for (i = 0; i < mux->preface->content_storage->n_packages; i++) {
338         MXFMetadataSourcePackage *package;
339
340         if (!MXF_IS_METADATA_SOURCE_PACKAGE (mux->preface->content_storage->
341                 packages[i]))
342           continue;
343
344         package =
345             MXF_METADATA_SOURCE_PACKAGE (mux->preface->content_storage->
346             packages[i]);
347
348         if (!package->descriptor)
349           continue;
350
351         if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor)) {
352           MXFMetadataMultipleDescriptor *tmp =
353               MXF_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor);
354
355           for (j = 0; j < tmp->n_sub_descriptors; j++) {
356             if (tmp->sub_descriptors[j] ==
357                 MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
358               tmp->sub_descriptors[j] =
359                   MXF_METADATA_GENERIC_DESCRIPTOR (cpad->descriptor);
360               memcpy (&tmp->sub_descriptors_uids[j], &d_instance_uid, 16);
361             }
362           }
363         } else if (package->descriptor ==
364             MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
365           package->descriptor =
366               MXF_METADATA_GENERIC_DESCRIPTOR (cpad->descriptor);
367           memcpy (&package->descriptor_uid, &d_instance_uid, 16);
368         }
369       }
370     }
371   }
372
373   gst_object_unref (mux);
374
375   return ret;
376 }
377
378 static char *
379 gst_mxf_mux_create_pad_name (GstPadTemplate * templ, guint id)
380 {
381   GString *string;
382
383   string = g_string_new (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
384   g_string_truncate (string, string->len - 2);
385   g_string_append_printf (string, "%u", id);
386
387   return g_string_free (string, FALSE);
388 }
389
390 static GstPad *
391 gst_mxf_mux_request_new_pad (GstElement * element,
392     GstPadTemplate * templ, const gchar * pad_name)
393 {
394   GstMXFMux *mux = GST_MXF_MUX (element);
395   GstMXFMuxPad *cpad;
396   GstPad *pad = NULL;
397   guint pad_number;
398   gchar *name = NULL;
399   const MXFEssenceElementWriter *writer;
400
401   if (mux->state != GST_MXF_MUX_STATE_HEADER) {
402     GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
403     return NULL;
404   }
405
406   writer = mxf_essence_element_writer_find (templ);
407   if (!writer) {
408     GST_ERROR_OBJECT (mux, "Not our template");
409     return NULL;
410   }
411 #if GLIB_CHECK_VERSION(2,29,5)
412   pad_number = g_atomic_int_add ((gint *) & mux->n_pads, 1);
413 #else
414   pad_number = g_atomic_int_exchange_and_add ((gint *) & mux->n_pads, 1);
415 #endif
416   name = gst_mxf_mux_create_pad_name (templ, pad_number);
417
418   GST_DEBUG_OBJECT (mux, "Creating pad '%s'", name);
419   pad = gst_pad_new_from_template (templ, name);
420   g_free (name);
421   cpad = (GstMXFMuxPad *)
422       gst_collect_pads_add_pad (mux->collect, pad, sizeof (GstMXFMuxPad));
423   cpad->last_timestamp = 0;
424   cpad->adapter = gst_adapter_new ();
425   cpad->writer = writer;
426
427   /* FIXME: hacked way to override/extend the event function of
428    * GstCollectPads; because it sets its own event function giving the
429    * element no access to events.
430    */
431   mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (pad);
432   gst_pad_set_event_function (pad,
433       GST_DEBUG_FUNCPTR (gst_mxf_mux_handle_sink_event));
434
435   gst_pad_set_setcaps_function (pad, gst_mxf_mux_setcaps);
436   gst_pad_use_fixed_caps (pad);
437   gst_pad_set_active (pad, TRUE);
438   gst_element_add_pad (element, pad);
439
440   return pad;
441 }
442
443 static void
444 gst_mxf_mux_release_pad (GstElement * element, GstPad * pad)
445 {
446   /*GstMXFMux *mux = GST_MXF_MUX (GST_PAD_PARENT (pad));
447      GstMXFMuxPad *cpad = (GstMXFMuxPad *) gst_pad_get_element_private (pad);
448
449      g_object_unref (cpad->adapter);
450      g_free (cpad->mapping_data);
451
452      gst_collect_pads_remove_pad (mux->collect, pad);
453      gst_element_remove_pad (element, pad); */
454 }
455
456 static GstFlowReturn
457 gst_mxf_mux_create_metadata (GstMXFMux * mux)
458 {
459   GstFlowReturn ret = GST_FLOW_OK;
460   GSList *l;
461   GArray *tmp;
462
463   GST_DEBUG_OBJECT (mux, "Creating MXF metadata");
464
465   for (l = mux->collect->data; l; l = l->next) {
466     GstMXFMuxPad *cpad = l->data;
467
468     if (!cpad || !cpad->descriptor || !GST_PAD_CAPS (cpad->collect.pad))
469       return GST_FLOW_ERROR;
470
471     if (cpad->writer->update_descriptor)
472       cpad->writer->update_descriptor (cpad->descriptor,
473           GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
474           cpad->collect.buffer);
475   }
476
477   /* Preface */
478   mux->preface =
479       (MXFMetadataPreface *) gst_mini_object_new (MXF_TYPE_METADATA_PREFACE);
480   mxf_uuid_init (&MXF_METADATA_BASE (mux->preface)->instance_uid,
481       mux->metadata);
482   g_hash_table_insert (mux->metadata,
483       &MXF_METADATA_BASE (mux->preface)->instance_uid, mux->preface);
484   mux->metadata_list = g_list_prepend (mux->metadata_list, mux->preface);
485
486   mxf_timestamp_set_now (&mux->preface->last_modified_date);
487   mux->preface->version = 258;
488   mux->preface->object_model_version = 1;
489
490   mxf_op_set_generalized (&mux->preface->operational_pattern, MXF_OP_1a, TRUE,
491       TRUE, FALSE);
492
493   tmp = g_array_new (FALSE, FALSE, sizeof (MXFUL));
494   for (l = mux->collect->data; l; l = l->next) {
495     GstMXFMuxPad *cpad = l->data;
496     guint i;
497     gboolean found = FALSE;
498
499     if (!cpad || !cpad->descriptor ||
500         mxf_ul_is_zero (&cpad->descriptor->essence_container))
501       return GST_FLOW_ERROR;
502
503     for (i = 0; i < tmp->len; i++) {
504       if (mxf_ul_is_equal (&cpad->descriptor->essence_container,
505               &g_array_index (tmp, MXFUL, i))) {
506         found = TRUE;
507         break;
508       }
509     }
510
511     if (found)
512       continue;
513
514     g_array_append_val (tmp, cpad->descriptor->essence_container);
515   }
516   mux->preface->n_essence_containers = tmp->len;
517   mux->preface->essence_containers = (MXFUL *) g_array_free (tmp, FALSE);
518
519   /* This will later be used as UID for the material package */
520   mxf_uuid_init (&mux->preface->primary_package_uid, mux->metadata);
521
522   /* Identifications */
523   {
524     MXFMetadataIdentification *identification;
525     static const guint8 gst_uid[] = {
526       0xe5, 0xde, 0xcd, 0x04, 0x24, 0x90, 0x69, 0x18,
527       0x8a, 0xc9, 0xb5, 0xd7, 0x02, 0x58, 0x46, 0x78
528     };
529     guint major, minor, micro, nano;
530
531     mux->preface->n_identifications = 1;
532     mux->preface->identifications = g_new0 (MXFMetadataIdentification *, 1);
533     identification = mux->preface->identifications[0] =
534         (MXFMetadataIdentification *)
535         gst_mini_object_new (MXF_TYPE_METADATA_IDENTIFICATION);
536
537     mxf_uuid_init (&MXF_METADATA_BASE (identification)->instance_uid,
538         mux->metadata);
539     g_hash_table_insert (mux->metadata,
540         &MXF_METADATA_BASE (identification)->instance_uid, identification);
541     mux->metadata_list = g_list_prepend (mux->metadata_list, identification);
542
543     mxf_uuid_init (&identification->this_generation_uid, NULL);
544
545     identification->company_name = g_strdup ("GStreamer");
546     identification->product_name = g_strdup ("GStreamer Multimedia Framework");
547
548     gst_version (&major, &minor, &micro, &nano);
549     identification->product_version.major = major;
550     identification->product_version.minor = minor;
551     identification->product_version.patch = micro;
552     identification->product_version.build = nano;
553     identification->product_version.release =
554         (nano == 0) ? 1 : (nano == 1) ? 2 : 4;
555
556     identification->version_string =
557         g_strdup_printf ("%u.%u.%u.%u", major, minor, micro, nano);
558     memcpy (&identification->product_uid, &gst_uid, 16);
559
560     memcpy (&identification->modification_date,
561         &mux->preface->last_modified_date, sizeof (MXFTimestamp));
562     memcpy (&identification->toolkit_version, &identification->product_version,
563         sizeof (MXFProductVersion));
564
565 #ifdef HAVE_SYS_UTSNAME_H
566     {
567       struct utsname sys_details;
568
569       if (uname (&sys_details) == 0) {
570         identification->platform = g_strdup_printf ("%s %s %s",
571             sys_details.sysname, sys_details.release, sys_details.machine);
572       }
573     }
574 #endif
575
576 #if defined(G_OS_WIN32)
577     if (identification->platform == NULL)
578       identification->platform = g_strdup ("Microsoft Windows");
579 #elif defined(G_OS_BEOS)
580     if (identification->platform == NULL)
581       identification->platform = g_strdup ("BEOS");
582 #elif defined(G_OS_UNIX)
583     if (identification->platform == NULL)
584       identification->platform = g_strdup ("Unix");
585 #endif
586   }
587
588   /* Content storage */
589   {
590     MXFMetadataContentStorage *cstorage;
591     guint i;
592
593     cstorage = mux->preface->content_storage = (MXFMetadataContentStorage *)
594         gst_mini_object_new (MXF_TYPE_METADATA_CONTENT_STORAGE);
595     mxf_uuid_init (&MXF_METADATA_BASE (cstorage)->instance_uid, mux->metadata);
596     g_hash_table_insert (mux->metadata,
597         &MXF_METADATA_BASE (cstorage)->instance_uid, cstorage);
598     mux->metadata_list = g_list_prepend (mux->metadata_list, cstorage);
599
600     cstorage->n_packages = 2;
601     cstorage->packages = g_new0 (MXFMetadataGenericPackage *, 2);
602
603     /* Source package */
604     {
605       MXFMetadataSourcePackage *p;
606
607       cstorage->packages[1] = (MXFMetadataGenericPackage *)
608           gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_PACKAGE);
609       mxf_uuid_init (&MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
610           mux->metadata);
611       g_hash_table_insert (mux->metadata,
612           &MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
613           cstorage->packages[1]);
614       mux->metadata_list =
615           g_list_prepend (mux->metadata_list, cstorage->packages[1]);
616       p = (MXFMetadataSourcePackage *) cstorage->packages[1];
617
618       mxf_umid_init (&p->parent.package_uid);
619       p->parent.name = g_strdup ("Source package");
620       memcpy (&p->parent.package_creation_date,
621           &mux->preface->last_modified_date, sizeof (MXFTimestamp));
622       memcpy (&p->parent.package_modified_date,
623           &mux->preface->last_modified_date, sizeof (MXFTimestamp));
624
625       p->parent.n_tracks = g_slist_length (mux->collect->data);
626       p->parent.tracks = g_new0 (MXFMetadataTrack *, p->parent.n_tracks);
627
628       if (p->parent.n_tracks > 1) {
629         MXFMetadataMultipleDescriptor *d;
630
631         p->descriptor = (MXFMetadataGenericDescriptor *)
632             gst_mini_object_new (MXF_TYPE_METADATA_MULTIPLE_DESCRIPTOR);
633         d = (MXFMetadataMultipleDescriptor *) p->descriptor;
634         d->n_sub_descriptors = p->parent.n_tracks;
635         d->sub_descriptors =
636             g_new0 (MXFMetadataGenericDescriptor *, p->parent.n_tracks);
637
638         mxf_uuid_init (&MXF_METADATA_BASE (d)->instance_uid, mux->metadata);
639         g_hash_table_insert (mux->metadata,
640             &MXF_METADATA_BASE (d)->instance_uid, d);
641         mux->metadata_list = g_list_prepend (mux->metadata_list, d);
642       }
643
644       /* Tracks */
645       {
646         guint n = 0;
647
648         /* Essence tracks */
649         for (l = mux->collect->data; l; l = l->next) {
650           GstMXFMuxPad *cpad = l->data;
651           MXFMetadataTimelineTrack *track;
652           MXFMetadataSequence *sequence;
653           MXFMetadataSourceClip *clip;
654
655           p->parent.tracks[n] = (MXFMetadataTrack *)
656               gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
657           track = (MXFMetadataTimelineTrack *) p->parent.tracks[n];
658           mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
659               mux->metadata);
660           g_hash_table_insert (mux->metadata,
661               &MXF_METADATA_BASE (track)->instance_uid, track);
662           mux->metadata_list = g_list_prepend (mux->metadata_list, track);
663
664           track->parent.track_id = n + 1;
665           track->parent.track_number =
666               cpad->writer->get_track_number_template (cpad->descriptor,
667               GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data);
668
669           cpad->writer->get_edit_rate (cpad->descriptor,
670               GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
671               cpad->collect.buffer, p, track, &track->edit_rate);
672
673           sequence = track->parent.sequence = (MXFMetadataSequence *)
674               gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
675           mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
676               mux->metadata);
677           g_hash_table_insert (mux->metadata,
678               &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
679           mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
680
681           memcpy (&sequence->data_definition, &cpad->writer->data_definition,
682               16);
683
684           sequence->n_structural_components = 1;
685           sequence->structural_components =
686               g_new0 (MXFMetadataStructuralComponent *, 1);
687
688           clip = (MXFMetadataSourceClip *)
689               gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_CLIP);
690           sequence->structural_components[0] =
691               (MXFMetadataStructuralComponent *) clip;
692           mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
693               mux->metadata);
694           g_hash_table_insert (mux->metadata,
695               &MXF_METADATA_BASE (clip)->instance_uid, clip);
696           mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
697
698           memcpy (&clip->parent.data_definition, &sequence->data_definition,
699               16);
700           clip->start_position = 0;
701
702           cpad->source_package = p;
703           cpad->source_track = track;
704           cpad->descriptor->linked_track_id = n + 1;
705           if (p->parent.n_tracks == 1) {
706             p->descriptor = (MXFMetadataGenericDescriptor *) cpad->descriptor;
707           } else {
708             MXF_METADATA_MULTIPLE_DESCRIPTOR (p->descriptor)->
709                 sub_descriptors[n] =
710                 (MXFMetadataGenericDescriptor *) cpad->descriptor;
711           }
712
713           n++;
714         }
715       }
716     }
717
718     /* Material package */
719     {
720       MXFMetadataMaterialPackage *p;
721       MXFFraction min_edit_rate = { 0, 0 };
722       gdouble min_edit_rate_d = G_MAXDOUBLE;
723
724       cstorage->packages[0] = (MXFMetadataGenericPackage *)
725           gst_mini_object_new (MXF_TYPE_METADATA_MATERIAL_PACKAGE);
726       memcpy (&MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
727           &mux->preface->primary_package_uid, 16);
728       g_hash_table_insert (mux->metadata,
729           &MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
730           cstorage->packages[0]);
731       mux->metadata_list =
732           g_list_prepend (mux->metadata_list, cstorage->packages[0]);
733       p = (MXFMetadataMaterialPackage *) cstorage->packages[0];
734
735       mxf_umid_init (&p->package_uid);
736       p->name = g_strdup ("Material package");
737       memcpy (&p->package_creation_date, &mux->preface->last_modified_date,
738           sizeof (MXFTimestamp));
739       memcpy (&p->package_modified_date, &mux->preface->last_modified_date,
740           sizeof (MXFTimestamp));
741
742       p->n_tracks = g_slist_length (mux->collect->data) + 1;
743       p->tracks = g_new0 (MXFMetadataTrack *, p->n_tracks);
744
745       /* Tracks */
746       {
747         guint n;
748
749         n = 1;
750         /* Essence tracks */
751         for (l = mux->collect->data; l; l = l->next) {
752           GstMXFMuxPad *cpad = l->data;
753           MXFMetadataSourcePackage *source_package;
754           MXFMetadataTimelineTrack *track, *source_track;
755           MXFMetadataSequence *sequence;
756           MXFMetadataSourceClip *clip;
757
758           source_package = MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
759           source_track =
760               MXF_METADATA_TIMELINE_TRACK (source_package->parent.tracks[n -
761                   1]);
762
763           p->tracks[n] = (MXFMetadataTrack *)
764               gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
765           track = (MXFMetadataTimelineTrack *) p->tracks[n];
766           mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
767               mux->metadata);
768           g_hash_table_insert (mux->metadata,
769               &MXF_METADATA_BASE (track)->instance_uid, track);
770           mux->metadata_list = g_list_prepend (mux->metadata_list, track);
771
772           track->parent.track_id = n + 1;
773           track->parent.track_number = 0;
774
775           cpad->writer->get_edit_rate (cpad->descriptor,
776               GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
777               cpad->collect.buffer, source_package, source_track,
778               &track->edit_rate);
779
780           if (track->edit_rate.n != source_track->edit_rate.n ||
781               track->edit_rate.d != source_track->edit_rate.d) {
782             memcpy (&source_track->edit_rate, &track->edit_rate,
783                 sizeof (MXFFraction));
784           }
785
786           if (track->edit_rate.d <= 0 || track->edit_rate.n <= 0) {
787             GST_ERROR_OBJECT (mux, "Invalid edit rate");
788             return GST_FLOW_ERROR;
789           }
790
791           if (min_edit_rate_d >
792               ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d)) {
793             min_edit_rate_d =
794                 ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d);
795             memcpy (&min_edit_rate, &track->edit_rate, sizeof (MXFFraction));
796           }
797
798           sequence = track->parent.sequence = (MXFMetadataSequence *)
799               gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
800           mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
801               mux->metadata);
802           g_hash_table_insert (mux->metadata,
803               &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
804           mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
805
806           memcpy (&sequence->data_definition, &cpad->writer->data_definition,
807               16);
808           sequence->n_structural_components = 1;
809           sequence->structural_components =
810               g_new0 (MXFMetadataStructuralComponent *, 1);
811
812           clip = (MXFMetadataSourceClip *)
813               gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_CLIP);
814           sequence->structural_components[0] =
815               (MXFMetadataStructuralComponent *) clip;
816           mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
817               mux->metadata);
818           g_hash_table_insert (mux->metadata,
819               &MXF_METADATA_BASE (clip)->instance_uid, clip);
820           mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
821
822           memcpy (&clip->parent.data_definition, &sequence->data_definition,
823               16);
824           clip->start_position = 0;
825
826           memcpy (&clip->source_package_id, &cstorage->packages[1]->package_uid,
827               32);
828           clip->source_track_id = n;
829
830           n++;
831         }
832
833         n = 0;
834         /* Timecode track */
835         {
836           MXFMetadataTimelineTrack *track;
837           MXFMetadataSequence *sequence;
838           MXFMetadataTimecodeComponent *component;
839
840           p->tracks[n] = (MXFMetadataTrack *)
841               gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
842           track = (MXFMetadataTimelineTrack *) p->tracks[n];
843           mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
844               mux->metadata);
845           g_hash_table_insert (mux->metadata,
846               &MXF_METADATA_BASE (track)->instance_uid, track);
847           mux->metadata_list = g_list_prepend (mux->metadata_list, track);
848
849           track->parent.track_id = n + 1;
850           track->parent.track_number = 0;
851           track->parent.track_name = g_strdup ("Timecode track");
852           /* FIXME: Is this correct? */
853           memcpy (&track->edit_rate, &min_edit_rate, sizeof (MXFFraction));
854
855           sequence = track->parent.sequence = (MXFMetadataSequence *)
856               gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
857           mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
858               mux->metadata);
859           g_hash_table_insert (mux->metadata,
860               &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
861           mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
862
863           memcpy (&sequence->data_definition,
864               mxf_metadata_track_identifier_get
865               (MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE), 16);
866
867           sequence->n_structural_components = 1;
868           sequence->structural_components =
869               g_new0 (MXFMetadataStructuralComponent *, 1);
870
871           component = (MXFMetadataTimecodeComponent *)
872               gst_mini_object_new (MXF_TYPE_METADATA_TIMECODE_COMPONENT);
873           sequence->structural_components[0] =
874               (MXFMetadataStructuralComponent *) component;
875           mxf_uuid_init (&MXF_METADATA_BASE (component)->instance_uid,
876               mux->metadata);
877           g_hash_table_insert (mux->metadata,
878               &MXF_METADATA_BASE (component)->instance_uid, component);
879           mux->metadata_list = g_list_prepend (mux->metadata_list, component);
880
881           memcpy (&component->parent.data_definition,
882               &sequence->data_definition, 16);
883
884           component->start_timecode = 0;
885           component->rounded_timecode_base =
886               (((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d) +
887               0.5);
888           /* TODO: drop frame */
889         }
890
891         memcpy (&mux->min_edit_rate, &min_edit_rate, sizeof (MXFFraction));
892       }
893     }
894
895     for (i = 0; i < cstorage->packages[1]->n_tracks; i++) {
896       MXFMetadataTrack *track = cstorage->packages[1]->tracks[i];
897       guint j;
898       guint32 templ;
899       guint8 n_type, n;
900
901       if ((track->track_number & 0x00ff00ff) != 0)
902         continue;
903
904       templ = track->track_number;
905       n_type = 0;
906
907       for (j = 0; j < cstorage->packages[1]->n_tracks; j++) {
908         MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
909
910         if (tmp->track_number == templ) {
911           n_type++;
912         }
913       }
914
915       n = 0;
916       for (j = 0; j < cstorage->packages[1]->n_tracks; j++) {
917         MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
918
919         if (tmp->track_number == templ) {
920           n++;
921           tmp->track_number |= (n_type << 16) | (n);
922         }
923       }
924     }
925
926     cstorage->n_essence_container_data = 1;
927     cstorage->essence_container_data =
928         g_new0 (MXFMetadataEssenceContainerData *, 1);
929     cstorage->essence_container_data[0] = (MXFMetadataEssenceContainerData *)
930         gst_mini_object_new (MXF_TYPE_METADATA_ESSENCE_CONTAINER_DATA);
931     mxf_uuid_init (&MXF_METADATA_BASE (cstorage->essence_container_data[0])->
932         instance_uid, mux->metadata);
933     g_hash_table_insert (mux->metadata,
934         &MXF_METADATA_BASE (cstorage->essence_container_data[0])->instance_uid,
935         cstorage->essence_container_data[0]);
936     mux->metadata_list =
937         g_list_prepend (mux->metadata_list,
938         cstorage->essence_container_data[0]);
939
940     cstorage->essence_container_data[0]->linked_package =
941         MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
942     cstorage->essence_container_data[0]->index_sid = 0;
943     cstorage->essence_container_data[0]->body_sid = 1;
944   }
945
946   /* Sort descriptors at the correct places */
947   {
948     GList *l;
949     GList *descriptors = NULL;
950
951     for (l = mux->metadata_list; l; l = l->next) {
952       MXFMetadataBase *m = l->data;
953
954       if (MXF_IS_METADATA_GENERIC_DESCRIPTOR (m)
955           && !MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m)) {
956         descriptors = l;
957         l->prev->next = NULL;
958         l->prev = NULL;
959         break;
960       }
961     }
962
963     g_assert (descriptors != NULL);
964
965     for (l = mux->metadata_list; l; l = l->next) {
966       MXFMetadataBase *m = l->data;
967       GList *s;
968
969       if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m) ||
970           MXF_IS_METADATA_SOURCE_PACKAGE (m)) {
971         s = l->prev;
972         l->prev = g_list_last (descriptors);
973         s->next = descriptors;
974         descriptors->prev = s;
975         l->prev->next = l;
976         break;
977       }
978     }
979   }
980
981   mux->metadata_list = g_list_reverse (mux->metadata_list);
982
983   return ret;
984 }
985
986 static GstFlowReturn
987 gst_mxf_mux_init_partition_pack (GstMXFMux * mux)
988 {
989   GSList *l;
990   guint i = 0;
991
992   mxf_partition_pack_reset (&mux->partition);
993   mux->partition.type = MXF_PARTITION_PACK_HEADER;
994   mux->partition.closed = mux->partition.complete = FALSE;
995   mux->partition.major_version = 0x0001;
996   mux->partition.minor_version = 0x0002;
997   mux->partition.kag_size = 0;
998   mux->partition.this_partition = 0;
999   mux->partition.prev_partition = 0;
1000   mux->partition.footer_partition = 0;
1001   mux->partition.header_byte_count = 0;
1002   mux->partition.index_byte_count = 0;
1003   mux->partition.index_sid = 0;
1004   mux->partition.body_offset = 0;
1005   mux->partition.body_sid = 0;
1006
1007   memcpy (&mux->partition.operational_pattern,
1008       &mux->preface->operational_pattern, 16);
1009
1010   mux->partition.n_essence_containers = g_slist_length (mux->collect->data);
1011   mux->partition.essence_containers =
1012       g_new0 (MXFUL, mux->partition.n_essence_containers);
1013
1014   for (l = mux->collect->data; l; l = l->next) {
1015     GstMXFMuxPad *cpad = l->data;
1016     guint j;
1017     gboolean found = FALSE;
1018
1019     for (j = 0; j <= i; j++) {
1020       if (mxf_ul_is_equal (&cpad->descriptor->essence_container,
1021               &mux->partition.essence_containers[j])) {
1022         found = TRUE;
1023         break;
1024       }
1025     }
1026
1027     if (found)
1028       continue;
1029
1030     memcpy (&mux->partition.essence_containers[i],
1031         &cpad->descriptor->essence_container, 16);
1032     i++;
1033   }
1034   mux->partition.n_essence_containers = i;
1035
1036   return GST_FLOW_OK;
1037 }
1038
1039 static GstFlowReturn
1040 gst_mxf_mux_write_header_metadata (GstMXFMux * mux)
1041 {
1042   GstFlowReturn ret = GST_FLOW_OK;
1043   GstBuffer *buf;
1044   GList *buffers = NULL;
1045   GList *l;
1046   MXFMetadataBase *m;
1047   guint64 header_byte_count = 0;
1048
1049   for (l = mux->metadata_list; l; l = l->next) {
1050     m = l->data;
1051     buf = mxf_metadata_base_to_buffer (m, &mux->primer);
1052     header_byte_count += GST_BUFFER_SIZE (buf);
1053     buffers = g_list_prepend (buffers, buf);
1054   }
1055
1056   buffers = g_list_reverse (buffers);
1057   buf = mxf_primer_pack_to_buffer (&mux->primer);
1058   header_byte_count += GST_BUFFER_SIZE (buf);
1059   buffers = g_list_prepend (buffers, buf);
1060
1061   mux->partition.header_byte_count = header_byte_count;
1062   buf = mxf_partition_pack_to_buffer (&mux->partition);
1063   if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1064     GST_ERROR_OBJECT (mux, "Failed pushing partition: %s",
1065         gst_flow_get_name (ret));
1066     g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
1067     g_list_free (buffers);
1068     return ret;
1069   }
1070
1071   for (l = buffers; l; l = l->next) {
1072     buf = l->data;
1073     l->data = NULL;
1074     if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1075       GST_ERROR_OBJECT (mux, "Failed pushing buffer: %s",
1076           gst_flow_get_name (ret));
1077       g_list_foreach (l, (GFunc) gst_mini_object_unref, NULL);
1078       g_list_free (buffers);
1079       return ret;
1080     }
1081   }
1082
1083   g_list_free (buffers);
1084
1085   return ret;
1086 }
1087
1088 static const guint8 _gc_essence_element_ul[] = {
1089   0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x00,
1090   0x0d, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00
1091 };
1092
1093 static GstFlowReturn
1094 gst_mxf_mux_handle_buffer (GstMXFMux * mux, GstMXFMuxPad * cpad)
1095 {
1096   GstBuffer *buf = NULL;
1097   GstBuffer *outbuf = NULL;
1098   GstBuffer *packet;
1099   GstFlowReturn ret = GST_FLOW_OK;
1100   guint8 slen, ber[9];
1101   gboolean flush =
1102       (cpad->collect.abidata.ABI.eos && !cpad->have_complete_edit_unit
1103       && cpad->collect.buffer == NULL);
1104
1105   if (cpad->have_complete_edit_unit) {
1106     GST_DEBUG_OBJECT (cpad->collect.pad,
1107         "Handling remaining buffer for track %u at position %" G_GINT64_FORMAT,
1108         cpad->source_track->parent.track_id, cpad->pos);
1109     buf = NULL;
1110   } else if (!flush) {
1111     buf = gst_collect_pads_pop (mux->collect, &cpad->collect);
1112   }
1113
1114   if (buf) {
1115     GST_DEBUG_OBJECT (cpad->collect.pad,
1116         "Handling buffer of size %u for track %u at position %" G_GINT64_FORMAT,
1117         GST_BUFFER_SIZE (buf), cpad->source_track->parent.track_id, cpad->pos);
1118   } else {
1119     flush = TRUE;
1120     GST_DEBUG_OBJECT (cpad->collect.pad,
1121         "Flushing for track %u at position %" G_GINT64_FORMAT,
1122         cpad->source_track->parent.track_id, cpad->pos);
1123   }
1124
1125   ret = cpad->write_func (buf, GST_PAD_CAPS (cpad->collect.pad),
1126       cpad->mapping_data, cpad->adapter, &outbuf, flush);
1127   if (ret != GST_FLOW_OK && ret != GST_FLOW_CUSTOM_SUCCESS) {
1128     GST_ERROR_OBJECT (cpad->collect.pad,
1129         "Failed handling buffer for track %u, reason %s",
1130         cpad->source_track->parent.track_id, gst_flow_get_name (ret));
1131     return ret;
1132   }
1133
1134   if (ret == GST_FLOW_CUSTOM_SUCCESS) {
1135     cpad->have_complete_edit_unit = TRUE;
1136     ret = GST_FLOW_OK;
1137   } else {
1138     cpad->have_complete_edit_unit = FALSE;
1139   }
1140
1141   buf = outbuf;
1142   if (buf == NULL)
1143     return ret;
1144
1145   slen = mxf_ber_encode_size (GST_BUFFER_SIZE (buf), ber);
1146   packet = gst_buffer_new_and_alloc (16 + slen + GST_BUFFER_SIZE (buf));
1147   memcpy (GST_BUFFER_DATA (packet), _gc_essence_element_ul, 16);
1148   GST_BUFFER_DATA (packet)[7] = cpad->descriptor->essence_container.u[7];
1149   GST_WRITE_UINT32_BE (&GST_BUFFER_DATA (packet)[12],
1150       cpad->source_track->parent.track_number);
1151   memcpy (&GST_BUFFER_DATA (packet)[16], ber, slen);
1152   memcpy (&GST_BUFFER_DATA (packet)[16 + slen], GST_BUFFER_DATA (buf),
1153       GST_BUFFER_SIZE (buf));
1154   gst_buffer_unref (buf);
1155
1156   GST_DEBUG_OBJECT (cpad->collect.pad, "Pushing buffer of size %u for track %u",
1157       GST_BUFFER_SIZE (packet), cpad->source_track->parent.track_id);
1158
1159   if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
1160     GST_ERROR_OBJECT (cpad->collect.pad,
1161         "Failed pushing buffer for track %u, reason %s",
1162         cpad->source_track->parent.track_id, gst_flow_get_name (ret));
1163     return ret;
1164   }
1165
1166   cpad->pos++;
1167   cpad->last_timestamp =
1168       gst_util_uint64_scale (GST_SECOND * cpad->pos,
1169       cpad->source_track->edit_rate.d, cpad->source_track->edit_rate.n);
1170
1171   return ret;
1172 }
1173
1174 static GstFlowReturn
1175 gst_mxf_mux_write_body_partition (GstMXFMux * mux)
1176 {
1177   GstBuffer *buf;
1178
1179   mux->partition.type = MXF_PARTITION_PACK_BODY;
1180   mux->partition.this_partition = mux->offset;
1181   mux->partition.prev_partition = 0;
1182   mux->partition.footer_partition = 0;
1183   mux->partition.header_byte_count = 0;
1184   mux->partition.index_byte_count = 0;
1185   mux->partition.index_sid = 0;
1186   mux->partition.body_offset = 0;
1187   mux->partition.body_sid =
1188       mux->preface->content_storage->essence_container_data[0]->body_sid;
1189
1190   buf = mxf_partition_pack_to_buffer (&mux->partition);
1191   return gst_mxf_mux_push (mux, buf);
1192 }
1193
1194 static GstFlowReturn
1195 gst_mxf_mux_handle_eos (GstMXFMux * mux)
1196 {
1197   GSList *l;
1198   gboolean have_data = FALSE;
1199   GstBuffer *packet;
1200
1201   do {
1202     GstMXFMuxPad *best = NULL;
1203
1204     have_data = FALSE;
1205
1206     for (l = mux->collect->data; l; l = l->next) {
1207       GstMXFMuxPad *cpad = l->data;
1208       GstClockTime next_gc_timestamp =
1209           gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1210           mux->min_edit_rate.d, mux->min_edit_rate.n);
1211
1212       best = NULL;
1213
1214       if (cpad->have_complete_edit_unit ||
1215           gst_adapter_available (cpad->adapter) > 0 || cpad->collect.buffer) {
1216         have_data = TRUE;
1217         if (cpad->last_timestamp < next_gc_timestamp) {
1218           best = cpad;
1219           break;
1220         }
1221       }
1222
1223       if (have_data && !l->next) {
1224         mux->last_gc_position++;
1225         mux->last_gc_timestamp = next_gc_timestamp;
1226         best = NULL;
1227         break;
1228       }
1229     }
1230
1231     if (best) {
1232       gst_mxf_mux_handle_buffer (mux, best);
1233       have_data = TRUE;
1234     }
1235   } while (have_data);
1236
1237   mux->last_gc_position++;
1238   mux->last_gc_timestamp =
1239       gst_util_uint64_scale (mux->last_gc_position * GST_SECOND,
1240       mux->min_edit_rate.d, mux->min_edit_rate.n);
1241
1242   /* Update essence track durations */
1243   for (l = mux->collect->data; l; l = l->next) {
1244     GstMXFMuxPad *cpad = l->data;
1245     guint i;
1246
1247     /* Update durations */
1248     cpad->source_track->parent.sequence->duration = cpad->pos;
1249     MXF_METADATA_SOURCE_CLIP (cpad->source_track->parent.sequence->
1250         structural_components[0])->parent.duration = cpad->pos;
1251     for (i = 0; i < mux->preface->content_storage->packages[0]->n_tracks; i++) {
1252       MXFMetadataTimelineTrack *track;
1253
1254       if (!MXF_IS_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
1255               packages[0]->tracks[i])
1256           || !MXF_IS_METADATA_SOURCE_CLIP (mux->preface->content_storage->
1257               packages[0]->tracks[i]->sequence->structural_components[0]))
1258         continue;
1259
1260       track =
1261           MXF_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
1262           packages[0]->tracks[i]);
1263       if (MXF_METADATA_SOURCE_CLIP (track->parent.sequence->
1264               structural_components[0])->source_track_id ==
1265           cpad->source_track->parent.track_id) {
1266         track->parent.sequence->structural_components[0]->duration = cpad->pos;
1267         track->parent.sequence->duration = cpad->pos;
1268       }
1269     }
1270   }
1271
1272   /* Update timecode track duration */
1273   {
1274     MXFMetadataTimelineTrack *track =
1275         MXF_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
1276         packages[0]->tracks[0]);
1277     MXFMetadataSequence *sequence = track->parent.sequence;
1278     MXFMetadataTimecodeComponent *component =
1279         MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1280
1281     sequence->duration = mux->last_gc_position;
1282     component->parent.duration = mux->last_gc_position;
1283   }
1284
1285   {
1286     guint64 body_partition = mux->partition.this_partition;
1287     guint32 body_sid = mux->partition.body_sid;
1288     guint64 footer_partition = mux->offset;
1289     GArray *rip;
1290     GstFlowReturn ret;
1291     MXFRandomIndexPackEntry entry;
1292
1293     mux->partition.type = MXF_PARTITION_PACK_FOOTER;
1294     mux->partition.closed = TRUE;
1295     mux->partition.complete = TRUE;
1296     mux->partition.this_partition = mux->offset;
1297     mux->partition.prev_partition = body_partition;
1298     mux->partition.footer_partition = mux->offset;
1299     mux->partition.header_byte_count = 0;
1300     mux->partition.index_byte_count = 0;
1301     mux->partition.index_sid = 0;
1302     mux->partition.body_offset = 0;
1303     mux->partition.body_sid = 0;
1304
1305     gst_mxf_mux_write_header_metadata (mux);
1306
1307     rip = g_array_sized_new (FALSE, FALSE, sizeof (MXFRandomIndexPackEntry), 3);
1308     entry.offset = 0;
1309     entry.body_sid = 0;
1310     g_array_append_val (rip, entry);
1311     entry.offset = body_partition;
1312     entry.body_sid = body_sid;
1313     g_array_append_val (rip, entry);
1314     entry.offset = footer_partition;
1315     entry.body_sid = 0;
1316     g_array_append_val (rip, entry);
1317
1318     packet = mxf_random_index_pack_to_buffer (rip);
1319     if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
1320       GST_ERROR_OBJECT (mux, "Failed pushing random index pack");
1321     }
1322     g_array_free (rip, TRUE);
1323
1324     /* Rewrite header partition with updated values */
1325     if (gst_pad_push_event (mux->srcpad,
1326             gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1,
1327                 0))) {
1328       mux->offset = 0;
1329       mux->partition.type = MXF_PARTITION_PACK_HEADER;
1330       mux->partition.closed = TRUE;
1331       mux->partition.complete = TRUE;
1332       mux->partition.this_partition = 0;
1333       mux->partition.prev_partition = footer_partition;
1334       mux->partition.footer_partition = footer_partition;
1335       mux->partition.header_byte_count = 0;
1336       mux->partition.index_byte_count = 0;
1337       mux->partition.index_sid = 0;
1338       mux->partition.body_offset = 0;
1339       mux->partition.body_sid = 0;
1340
1341       ret = gst_mxf_mux_write_header_metadata (mux);
1342       if (ret != GST_FLOW_OK) {
1343         GST_ERROR_OBJECT (mux, "Rewriting header partition failed");
1344         return ret;
1345       }
1346     } else {
1347       GST_WARNING_OBJECT (mux, "Can't rewrite header partition");
1348     }
1349   }
1350
1351   return GST_FLOW_OK;
1352 }
1353
1354 static gint
1355 _sort_mux_pads (gconstpointer a, gconstpointer b)
1356 {
1357   const GstMXFMuxPad *pa = a, *pb = b;
1358   MXFMetadataTrackType ta =
1359       mxf_metadata_track_identifier_parse (&pa->writer->data_definition);
1360   MXFMetadataTrackType tb =
1361       mxf_metadata_track_identifier_parse (&pb->writer->data_definition);
1362
1363   if (ta != tb)
1364     return ta - tb;
1365
1366   return pa->source_track->parent.track_number -
1367       pa->source_track->parent.track_number;
1368 }
1369
1370 static GstFlowReturn
1371 gst_mxf_mux_collected (GstCollectPads * pads, gpointer user_data)
1372 {
1373   GstMXFMux *mux = GST_MXF_MUX (user_data);
1374   GstMXFMuxPad *best = NULL;
1375   GstFlowReturn ret;
1376   GSList *sl;
1377   gboolean eos = TRUE;
1378
1379   if (mux->state == GST_MXF_MUX_STATE_ERROR) {
1380     GST_ERROR_OBJECT (mux, "Had an error before -- returning");
1381     return GST_FLOW_ERROR;
1382   } else if (mux->state == GST_MXF_MUX_STATE_EOS) {
1383     GST_WARNING_OBJECT (mux, "EOS");
1384     return GST_FLOW_UNEXPECTED;
1385   }
1386
1387   if (mux->state == GST_MXF_MUX_STATE_HEADER) {
1388     if (mux->collect->data == NULL) {
1389       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1390           ("No input streams configured"));
1391       ret = GST_FLOW_ERROR;
1392       goto error;
1393     }
1394
1395     if (gst_pad_push_event (mux->srcpad,
1396             gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1,
1397                 0))) {
1398       if ((ret = gst_mxf_mux_create_metadata (mux)) != GST_FLOW_OK)
1399         goto error;
1400
1401       if ((ret = gst_mxf_mux_init_partition_pack (mux)) != GST_FLOW_OK)
1402         goto error;
1403
1404       ret = gst_mxf_mux_write_header_metadata (mux);
1405     } else {
1406       ret = GST_FLOW_ERROR;
1407     }
1408
1409     if (ret != GST_FLOW_OK)
1410       goto error;
1411
1412     /* Sort pads, we will always write in that order */
1413     mux->collect->data = g_slist_sort (mux->collect->data, _sort_mux_pads);
1414
1415     /* Write body partition */
1416     ret = gst_mxf_mux_write_body_partition (mux);
1417     if (ret != GST_FLOW_OK)
1418       goto error;
1419     mux->state = GST_MXF_MUX_STATE_DATA;
1420   }
1421
1422   g_return_val_if_fail (g_hash_table_size (mux->metadata) > 0, GST_FLOW_ERROR);
1423
1424   do {
1425     for (sl = mux->collect->data; sl; sl = sl->next) {
1426       GstMXFMuxPad *cpad = sl->data;
1427       GstClockTime next_gc_timestamp =
1428           gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1429           mux->min_edit_rate.d, mux->min_edit_rate.n);
1430
1431       eos &= cpad->collect.abidata.ABI.eos;
1432
1433       if ((!cpad->collect.abidata.ABI.eos || cpad->have_complete_edit_unit ||
1434               gst_adapter_available (cpad->adapter) > 0 || cpad->collect.buffer)
1435           && cpad->last_timestamp < next_gc_timestamp) {
1436         best = cpad;
1437         break;
1438       } else if (!eos && !sl->next) {
1439         mux->last_gc_position++;
1440         mux->last_gc_timestamp = next_gc_timestamp;
1441         eos = FALSE;
1442         best = NULL;
1443         break;
1444       }
1445     }
1446   } while (!eos && best == NULL);
1447
1448   if (!eos && best) {
1449     ret = gst_mxf_mux_handle_buffer (mux, best);
1450     if (ret != GST_FLOW_OK)
1451       goto error;
1452   } else if (eos) {
1453     GST_DEBUG_OBJECT (mux, "Handling EOS");
1454
1455     gst_mxf_mux_handle_eos (mux);
1456     gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
1457     mux->state = GST_MXF_MUX_STATE_EOS;
1458     return GST_FLOW_UNEXPECTED;
1459   }
1460
1461   return GST_FLOW_OK;
1462
1463 error:
1464   {
1465     mux->state = GST_MXF_MUX_STATE_ERROR;
1466     gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
1467     return ret;
1468   }
1469 }
1470
1471 static GstStateChangeReturn
1472 gst_mxf_mux_change_state (GstElement * element, GstStateChange transition)
1473 {
1474   GstStateChangeReturn ret;
1475   GstMXFMux *mux = GST_MXF_MUX (element);
1476
1477   switch (transition) {
1478     case GST_STATE_CHANGE_NULL_TO_READY:
1479       break;
1480     case GST_STATE_CHANGE_READY_TO_PAUSED:
1481       gst_collect_pads_start (mux->collect);
1482       break;
1483     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1484       break;
1485     case GST_STATE_CHANGE_PAUSED_TO_READY:
1486       gst_collect_pads_stop (mux->collect);
1487       break;
1488     default:
1489       break;
1490   }
1491
1492   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1493
1494   switch (transition) {
1495     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1496       break;
1497     case GST_STATE_CHANGE_PAUSED_TO_READY:
1498       gst_mxf_mux_reset (mux);
1499       break;
1500     case GST_STATE_CHANGE_READY_TO_NULL:
1501       break;
1502     default:
1503       break;
1504   }
1505
1506   return ret;
1507 }