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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /**
21  * SECTION:element-mxfmux
22  * @title: mxfmux
23  *
24  * mxfmux muxes different streams into an MXF file.
25  *
26  * ## Example launch line
27  * |[
28  * gst-launch-1.0 -v filesrc location=/path/to/audio ! decodebin ! queue ! mxfmux name=m ! filesink location=file.mxf   filesrc location=/path/to/video ! decodebin ! queue ! m.
29  * ]| This pipeline muxes an audio and video file into a single MXF file.
30  *
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 #define GST_TYPE_MXF_MUX_PAD            (gst_mxf_mux_pad_get_type())
50 #define GST_MXF_MUX_PAD(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MXF_MUX_PAD, GstMXFMuxPad))
51 #define GST_MXF_MUX_PAD_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MXF_MUX_PAD, GstMXFMuxPadClass))
52 #define GST_MXF_MUX_PAD_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_MXF_MUX_PAD, GstMXFMuxPadClass))
53 #define GST_IS_MXF_MUX_PAD(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MXF_MUX_PAD))
54 #define GST_IS_MXF_MUX_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MXF_MUX_PAD))
55 
56 typedef struct
57 {
58   GstAggregatorPad parent;
59 
60   guint64 pos;
61   GstClockTime last_timestamp;
62 
63   MXFMetadataFileDescriptor *descriptor;
64 
65   GstAdapter *adapter;
66   gboolean have_complete_edit_unit;
67 
68   gpointer mapping_data;
69   const MXFEssenceElementWriter *writer;
70   MXFEssenceElementWriteFunc write_func;
71 
72   MXFMetadataSourcePackage *source_package;
73   MXFMetadataTimelineTrack *source_track;
74 } GstMXFMuxPad;
75 
76 typedef struct
77 {
78   GstAggregatorPadClass parent_class;
79 } GstMXFMuxPadClass;
80 
81 GType gst_mxf_mux_pad_get_type (void);
82 
83 G_DEFINE_TYPE (GstMXFMuxPad, gst_mxf_mux_pad, GST_TYPE_AGGREGATOR_PAD);
84 
85 static void
gst_mxf_mux_pad_finalize(GObject * object)86 gst_mxf_mux_pad_finalize (GObject * object)
87 {
88   GstMXFMuxPad *pad = GST_MXF_MUX_PAD (object);
89 
90   g_object_unref (pad->adapter);
91   g_free (pad->mapping_data);
92 
93   G_OBJECT_CLASS (gst_mxf_mux_pad_parent_class)->finalize (object);
94 }
95 
96 static void
gst_mxf_mux_pad_class_init(GstMXFMuxPadClass * klass)97 gst_mxf_mux_pad_class_init (GstMXFMuxPadClass * klass)
98 {
99   GObjectClass *object_class = (GObjectClass *) klass;
100 
101   object_class->finalize = gst_mxf_mux_pad_finalize;
102 }
103 
104 static void
gst_mxf_mux_pad_init(GstMXFMuxPad * pad)105 gst_mxf_mux_pad_init (GstMXFMuxPad * pad)
106 {
107   pad->adapter = gst_adapter_new ();
108 }
109 
110 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
111     GST_PAD_SRC,
112     GST_PAD_ALWAYS,
113     GST_STATIC_CAPS ("application/mxf")
114     );
115 
116 enum
117 {
118   PROP_0
119 };
120 
121 #define gst_mxf_mux_parent_class parent_class
122 G_DEFINE_TYPE (GstMXFMux, gst_mxf_mux, GST_TYPE_AGGREGATOR);
123 
124 static void gst_mxf_mux_finalize (GObject * object);
125 
126 static GstFlowReturn gst_mxf_mux_aggregate (GstAggregator * aggregator,
127     gboolean timeout);
128 static gboolean gst_mxf_mux_stop (GstAggregator * aggregator);
129 
130 static gboolean gst_mxf_mux_src_event (GstAggregator * aggregator,
131     GstEvent * event);
132 static gboolean gst_mxf_mux_sink_event (GstAggregator * aggregator,
133     GstAggregatorPad * aggpad, GstEvent * event);
134 static GstAggregatorPad *gst_mxf_mux_create_new_pad (GstAggregator * aggregator,
135     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
136 
137 static void gst_mxf_mux_reset (GstMXFMux * mux);
138 
139 static GstFlowReturn
gst_mxf_mux_push(GstMXFMux * mux,GstBuffer * buf)140 gst_mxf_mux_push (GstMXFMux * mux, GstBuffer * buf)
141 {
142   guint size = gst_buffer_get_size (buf);
143   GstFlowReturn ret;
144 
145   ret = gst_aggregator_finish_buffer (GST_AGGREGATOR (mux), buf);
146   mux->offset += size;
147 
148   return ret;
149 }
150 
151 static void
gst_mxf_mux_class_init(GstMXFMuxClass * klass)152 gst_mxf_mux_class_init (GstMXFMuxClass * klass)
153 {
154   GObjectClass *gobject_class;
155   GstElementClass *gstelement_class;
156   GstAggregatorClass *gstaggregator_class;
157   const GstPadTemplate **p;
158 
159   GST_DEBUG_CATEGORY_INIT (mxfmux_debug, "mxfmux", 0, "MXF muxer");
160 
161   gobject_class = (GObjectClass *) klass;
162   gstelement_class = (GstElementClass *) klass;
163   gstaggregator_class = (GstAggregatorClass *) klass;
164 
165   gobject_class->finalize = gst_mxf_mux_finalize;
166 
167   gstaggregator_class->create_new_pad =
168       GST_DEBUG_FUNCPTR (gst_mxf_mux_create_new_pad);
169   gstaggregator_class->src_event = GST_DEBUG_FUNCPTR (gst_mxf_mux_src_event);
170   gstaggregator_class->sink_event = GST_DEBUG_FUNCPTR (gst_mxf_mux_sink_event);
171   gstaggregator_class->stop = GST_DEBUG_FUNCPTR (gst_mxf_mux_stop);
172   gstaggregator_class->aggregate = GST_DEBUG_FUNCPTR (gst_mxf_mux_aggregate);
173 
174   gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
175       &src_templ, GST_TYPE_MXF_MUX_PAD);
176 
177   p = mxf_essence_element_writer_get_pad_templates ();
178   while (p && *p) {
179     gst_element_class_add_pad_template (gstelement_class,
180         (GstPadTemplate *) gst_object_ref (GST_OBJECT (*p)));
181     p++;
182   }
183 
184   gst_element_class_set_static_metadata (gstelement_class, "MXF muxer",
185       "Codec/Muxer",
186       "Muxes video/audio streams into a MXF stream",
187       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
188 }
189 
190 static void
gst_mxf_mux_init(GstMXFMux * mux)191 gst_mxf_mux_init (GstMXFMux * mux)
192 {
193   mux->index_table = g_array_new (FALSE, FALSE, sizeof (MXFIndexTableSegment));
194   gst_mxf_mux_reset (mux);
195 }
196 
197 static void
gst_mxf_mux_finalize(GObject * object)198 gst_mxf_mux_finalize (GObject * object)
199 {
200   GstMXFMux *mux = GST_MXF_MUX (object);
201 
202   gst_mxf_mux_reset (mux);
203 
204   if (mux->metadata) {
205     g_hash_table_destroy (mux->metadata);
206     mux->metadata = NULL;
207     g_list_free (mux->metadata_list);
208     mux->metadata_list = NULL;
209   }
210 
211   if (mux->index_table) {
212     gsize n;
213     for (n = 0; n < mux->index_table->len; ++n)
214       g_free (g_array_index (mux->index_table, MXFIndexTableSegment,
215               n).index_entries);
216     g_array_free (mux->index_table, TRUE);
217     mux->index_table = NULL;
218   }
219 
220   G_OBJECT_CLASS (parent_class)->finalize (object);
221 }
222 
223 static void
gst_mxf_mux_reset(GstMXFMux * mux)224 gst_mxf_mux_reset (GstMXFMux * mux)
225 {
226   GList *l;
227   gsize n;
228 
229   GST_OBJECT_LOCK (mux);
230   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
231     GstMXFMuxPad *pad = l->data;
232 
233     gst_adapter_clear (pad->adapter);
234     g_free (pad->mapping_data);
235     pad->mapping_data = NULL;
236 
237     pad->pos = 0;
238     pad->last_timestamp = 0;
239     pad->descriptor = NULL;
240     pad->have_complete_edit_unit = FALSE;
241 
242     pad->source_package = NULL;
243     pad->source_track = NULL;
244   }
245   GST_OBJECT_UNLOCK (mux);
246 
247   mux->state = GST_MXF_MUX_STATE_HEADER;
248 
249   if (mux->metadata) {
250     g_hash_table_destroy (mux->metadata);
251     mux->preface = NULL;
252     g_list_free (mux->metadata_list);
253     mux->metadata_list = NULL;
254   }
255   mux->metadata = mxf_metadata_hash_table_new ();
256 
257   mxf_partition_pack_reset (&mux->partition);
258   mxf_primer_pack_reset (&mux->primer);
259   memset (&mux->min_edit_rate, 0, sizeof (MXFFraction));
260   mux->last_gc_timestamp = 0;
261   mux->last_gc_position = 0;
262   mux->offset = 0;
263 
264   if (mux->index_table)
265     for (n = 0; n < mux->index_table->len; ++n)
266       g_free (g_array_index (mux->index_table, MXFIndexTableSegment,
267               n).index_entries);
268   g_array_set_size (mux->index_table, 0);
269   mux->current_index_pos = 0;
270   mux->last_keyframe_pos = 0;
271 }
272 
273 static gboolean
gst_mxf_mux_src_event(GstAggregator * aggregator,GstEvent * event)274 gst_mxf_mux_src_event (GstAggregator * aggregator, GstEvent * event)
275 {
276   switch (GST_EVENT_TYPE (event)) {
277     case GST_EVENT_SEEK:
278       /* disable seeking for now */
279       gst_event_unref (event);
280       return FALSE;
281     default:
282       return GST_AGGREGATOR_CLASS (parent_class)->src_event (aggregator, event);
283       break;
284   }
285 
286   g_assert_not_reached ();
287 }
288 
289 static gboolean
gst_mxf_mux_set_caps(GstMXFMux * mux,GstMXFMuxPad * pad,GstCaps * caps)290 gst_mxf_mux_set_caps (GstMXFMux * mux, GstMXFMuxPad * pad, GstCaps * caps)
291 {
292   gboolean ret = TRUE;
293   MXFUUID d_instance_uid = { {0,} };
294   MXFMetadataFileDescriptor *old_descriptor = pad->descriptor;
295   GList *l;
296 
297   GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps);
298 
299   if (old_descriptor) {
300     memcpy (&d_instance_uid, &MXF_METADATA_BASE (old_descriptor)->instance_uid,
301         16);
302     pad->descriptor = NULL;
303     g_free (pad->mapping_data);
304     pad->mapping_data = NULL;
305   }
306 
307   pad->descriptor =
308       pad->writer->get_descriptor (GST_PAD_PAD_TEMPLATE (pad), caps,
309       &pad->write_func, &pad->mapping_data);
310 
311   if (!pad->descriptor) {
312     GST_ERROR_OBJECT (mux,
313         "Couldn't get descriptor for pad '%s' with caps %" GST_PTR_FORMAT,
314         GST_PAD_NAME (pad), caps);
315     return FALSE;
316   }
317 
318   if (mxf_uuid_is_zero (&d_instance_uid))
319     mxf_uuid_init (&d_instance_uid, mux->metadata);
320 
321   memcpy (&MXF_METADATA_BASE (pad->descriptor)->instance_uid, &d_instance_uid,
322       16);
323 
324   if (old_descriptor) {
325     for (l = mux->metadata_list; l; l = l->next) {
326       MXFMetadataBase *tmp = l->data;
327 
328       if (mxf_uuid_is_equal (&d_instance_uid, &tmp->instance_uid)) {
329         l->data = pad->descriptor;
330         break;
331       }
332     }
333   } else {
334     mux->metadata_list = g_list_prepend (mux->metadata_list, pad->descriptor);
335   }
336 
337   g_hash_table_replace (mux->metadata,
338       &MXF_METADATA_BASE (pad->descriptor)->instance_uid, pad->descriptor);
339 
340   if (old_descriptor) {
341     if (mux->preface && mux->preface->content_storage &&
342         mux->preface->content_storage->packages) {
343       guint i, j;
344 
345       for (i = 0; i < mux->preface->content_storage->n_packages; i++) {
346         MXFMetadataSourcePackage *package;
347 
348         if (!MXF_IS_METADATA_SOURCE_PACKAGE (mux->preface->
349                 content_storage->packages[i]))
350           continue;
351 
352         package =
353             MXF_METADATA_SOURCE_PACKAGE (mux->preface->
354             content_storage->packages[i]);
355 
356         if (!package->descriptor)
357           continue;
358 
359         if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor)) {
360           MXFMetadataMultipleDescriptor *tmp =
361               MXF_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor);
362 
363           for (j = 0; j < tmp->n_sub_descriptors; j++) {
364             if (tmp->sub_descriptors[j] ==
365                 MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
366               tmp->sub_descriptors[j] =
367                   MXF_METADATA_GENERIC_DESCRIPTOR (pad->descriptor);
368               memcpy (&tmp->sub_descriptors_uids[j], &d_instance_uid, 16);
369             }
370           }
371         } else if (package->descriptor ==
372             MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
373           package->descriptor =
374               MXF_METADATA_GENERIC_DESCRIPTOR (pad->descriptor);
375           memcpy (&package->descriptor_uid, &d_instance_uid, 16);
376         }
377       }
378     }
379   }
380 
381   return ret;
382 }
383 
384 static gboolean
gst_mxf_mux_sink_event(GstAggregator * aggregator,GstAggregatorPad * aggpad,GstEvent * event)385 gst_mxf_mux_sink_event (GstAggregator * aggregator,
386     GstAggregatorPad * aggpad, GstEvent * event)
387 {
388   GstMXFMux *mux = GST_MXF_MUX (aggregator);
389   gboolean ret = TRUE;
390 
391   switch (GST_EVENT_TYPE (event)) {
392     case GST_EVENT_TAG:
393       /* TODO: do something with the tags */
394       break;
395     case GST_EVENT_CAPS:{
396       GstCaps *caps;
397 
398       gst_event_parse_caps (event, &caps);
399 
400       ret = gst_mxf_mux_set_caps (mux, GST_MXF_MUX_PAD (aggpad), caps);
401 
402       break;
403     }
404     default:
405       break;
406   }
407 
408   /* now GstAggregator can take care of the rest, e.g. EOS */
409   if (ret)
410     ret =
411         GST_AGGREGATOR_CLASS (parent_class)->sink_event (aggregator, aggpad,
412         event);
413 
414   return ret;
415 }
416 
417 static char *
gst_mxf_mux_create_pad_name(GstPadTemplate * templ,guint id)418 gst_mxf_mux_create_pad_name (GstPadTemplate * templ, guint id)
419 {
420   GString *string;
421 
422   string = g_string_new (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
423   g_string_truncate (string, string->len - 2);
424   g_string_append_printf (string, "%u", id);
425 
426   return g_string_free (string, FALSE);
427 }
428 
429 static GstAggregatorPad *
gst_mxf_mux_create_new_pad(GstAggregator * aggregator,GstPadTemplate * templ,const gchar * pad_name,const GstCaps * caps)430 gst_mxf_mux_create_new_pad (GstAggregator * aggregator,
431     GstPadTemplate * templ, const gchar * pad_name, const GstCaps * caps)
432 {
433   GstMXFMux *mux = GST_MXF_MUX (aggregator);
434   GstMXFMuxPad *pad;
435   guint pad_number;
436   gchar *name = NULL;
437   const MXFEssenceElementWriter *writer;
438 
439   if (mux->state != GST_MXF_MUX_STATE_HEADER) {
440     GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
441     return NULL;
442   }
443 
444   writer = mxf_essence_element_writer_find (templ);
445   if (!writer) {
446     GST_ERROR_OBJECT (mux, "Not our template");
447     return NULL;
448   }
449   pad_number = g_atomic_int_add ((gint *) & mux->n_pads, 1);
450   name = gst_mxf_mux_create_pad_name (templ, pad_number);
451 
452   GST_DEBUG_OBJECT (mux, "Creating pad '%s'", name);
453   pad =
454       g_object_new (GST_TYPE_MXF_MUX_PAD, "name", name, "direction",
455       GST_PAD_SINK, "template", templ, NULL);
456   g_free (name);
457   pad->last_timestamp = 0;
458   pad->writer = writer;
459 
460   gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
461 
462   return GST_AGGREGATOR_PAD (pad);
463 }
464 
465 static GstFlowReturn
gst_mxf_mux_create_metadata(GstMXFMux * mux)466 gst_mxf_mux_create_metadata (GstMXFMux * mux)
467 {
468   GstFlowReturn ret = GST_FLOW_OK;
469   GList *l;
470   GArray *tmp;
471 
472   GST_DEBUG_OBJECT (mux, "Creating MXF metadata");
473 
474   GST_OBJECT_LOCK (mux);
475 
476   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
477     GstMXFMuxPad *pad = l->data;
478     GstCaps *caps;
479     GstBuffer *buffer;
480 
481     if (!pad || !pad->descriptor) {
482       GST_OBJECT_UNLOCK (mux);
483       return GST_FLOW_ERROR;
484     }
485 
486     caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
487     if (!caps) {
488       GST_OBJECT_UNLOCK (mux);
489       return GST_FLOW_ERROR;
490     }
491 
492     buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
493     if (pad->writer->update_descriptor)
494       pad->writer->update_descriptor (pad->descriptor,
495           caps, pad->mapping_data, buffer);
496     if (buffer)
497       gst_buffer_unref (buffer);
498     gst_caps_unref (caps);
499   }
500 
501   /* Preface */
502   mux->preface =
503       (MXFMetadataPreface *) g_object_new (MXF_TYPE_METADATA_PREFACE, NULL);
504   mxf_uuid_init (&MXF_METADATA_BASE (mux->preface)->instance_uid,
505       mux->metadata);
506   g_hash_table_insert (mux->metadata,
507       &MXF_METADATA_BASE (mux->preface)->instance_uid, mux->preface);
508   mux->metadata_list = g_list_prepend (mux->metadata_list, mux->preface);
509 
510   mxf_timestamp_set_now (&mux->preface->last_modified_date);
511   mux->preface->version = 258;
512   mux->preface->object_model_version = 1;
513 
514   mxf_op_set_generalized (&mux->preface->operational_pattern, MXF_OP_1a, TRUE,
515       TRUE, FALSE);
516 
517   tmp = g_array_new (FALSE, FALSE, sizeof (MXFUL));
518   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
519     GstMXFMuxPad *pad = l->data;
520     guint i;
521     gboolean found = FALSE;
522 
523     if (!pad || !pad->descriptor ||
524         mxf_ul_is_zero (&pad->descriptor->essence_container)) {
525       GST_OBJECT_UNLOCK (mux);
526       return GST_FLOW_ERROR;
527     }
528 
529     for (i = 0; i < tmp->len; i++) {
530       if (mxf_ul_is_equal (&pad->descriptor->essence_container,
531               &g_array_index (tmp, MXFUL, i))) {
532         found = TRUE;
533         break;
534       }
535     }
536 
537     if (found)
538       continue;
539 
540     g_array_append_val (tmp, pad->descriptor->essence_container);
541   }
542   mux->preface->n_essence_containers = tmp->len;
543   mux->preface->essence_containers = (MXFUL *) g_array_free (tmp, FALSE);
544 
545   /* This will later be used as UID for the material package */
546   mxf_uuid_init (&mux->preface->primary_package_uid, mux->metadata);
547 
548   /* Identifications */
549   {
550     MXFMetadataIdentification *identification;
551     static const guint8 gst_uid[] = {
552       0xe5, 0xde, 0xcd, 0x04, 0x24, 0x90, 0x69, 0x18,
553       0x8a, 0xc9, 0xb5, 0xd7, 0x02, 0x58, 0x46, 0x78
554     };
555     guint major, minor, micro, nano;
556 
557     mux->preface->n_identifications = 1;
558     mux->preface->identifications = g_new0 (MXFMetadataIdentification *, 1);
559     identification = mux->preface->identifications[0] =
560         (MXFMetadataIdentification *)
561         g_object_new (MXF_TYPE_METADATA_IDENTIFICATION, NULL);
562 
563     mxf_uuid_init (&MXF_METADATA_BASE (identification)->instance_uid,
564         mux->metadata);
565     g_hash_table_insert (mux->metadata,
566         &MXF_METADATA_BASE (identification)->instance_uid, identification);
567     mux->metadata_list = g_list_prepend (mux->metadata_list, identification);
568 
569     mxf_uuid_init (&identification->this_generation_uid, NULL);
570 
571     identification->company_name = g_strdup ("GStreamer");
572     identification->product_name = g_strdup ("GStreamer Multimedia Framework");
573 
574     gst_version (&major, &minor, &micro, &nano);
575     identification->product_version.major = major;
576     identification->product_version.minor = minor;
577     identification->product_version.patch = micro;
578     identification->product_version.build = nano;
579     identification->product_version.release =
580         (nano == 0) ? 1 : (nano == 1) ? 2 : 4;
581 
582     identification->version_string =
583         g_strdup_printf ("%u.%u.%u.%u", major, minor, micro, nano);
584     memcpy (&identification->product_uid, &gst_uid, 16);
585 
586     memcpy (&identification->modification_date,
587         &mux->preface->last_modified_date, sizeof (MXFTimestamp));
588     memcpy (&identification->toolkit_version, &identification->product_version,
589         sizeof (MXFProductVersion));
590 
591 #ifdef HAVE_SYS_UTSNAME_H
592     {
593       struct utsname sys_details;
594 
595       if (uname (&sys_details) == 0) {
596         identification->platform = g_strdup_printf ("%s %s %s",
597             sys_details.sysname, sys_details.release, sys_details.machine);
598       }
599     }
600 #endif
601 
602 #if defined(G_OS_WIN32)
603     if (identification->platform == NULL)
604       identification->platform = g_strdup ("Microsoft Windows");
605 #elif defined(G_OS_BEOS)
606     if (identification->platform == NULL)
607       identification->platform = g_strdup ("BEOS");
608 #elif defined(G_OS_UNIX)
609     if (identification->platform == NULL)
610       identification->platform = g_strdup ("Unix");
611 #endif
612   }
613 
614   /* Content storage */
615   {
616     MXFMetadataContentStorage *cstorage;
617     guint i;
618 
619     cstorage = mux->preface->content_storage = (MXFMetadataContentStorage *)
620         g_object_new (MXF_TYPE_METADATA_CONTENT_STORAGE, NULL);
621     mxf_uuid_init (&MXF_METADATA_BASE (cstorage)->instance_uid, mux->metadata);
622     g_hash_table_insert (mux->metadata,
623         &MXF_METADATA_BASE (cstorage)->instance_uid, cstorage);
624     mux->metadata_list = g_list_prepend (mux->metadata_list, cstorage);
625 
626     cstorage->n_packages = 2;
627     cstorage->packages = g_new0 (MXFMetadataGenericPackage *, 2);
628 
629     /* Source package */
630     {
631       MXFMetadataSourcePackage *p;
632 
633       cstorage->packages[1] = (MXFMetadataGenericPackage *)
634           g_object_new (MXF_TYPE_METADATA_SOURCE_PACKAGE, NULL);
635       mxf_uuid_init (&MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
636           mux->metadata);
637       g_hash_table_insert (mux->metadata,
638           &MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
639           cstorage->packages[1]);
640       mux->metadata_list =
641           g_list_prepend (mux->metadata_list, cstorage->packages[1]);
642       p = (MXFMetadataSourcePackage *) cstorage->packages[1];
643 
644       mxf_umid_init (&p->parent.package_uid);
645       p->parent.name = g_strdup ("Source package");
646       memcpy (&p->parent.package_creation_date,
647           &mux->preface->last_modified_date, sizeof (MXFTimestamp));
648       memcpy (&p->parent.package_modified_date,
649           &mux->preface->last_modified_date, sizeof (MXFTimestamp));
650 
651       p->parent.n_tracks = GST_ELEMENT_CAST (mux)->numsinkpads + 1;
652       p->parent.tracks = g_new0 (MXFMetadataTrack *, p->parent.n_tracks);
653 
654       if (p->parent.n_tracks > 2) {
655         MXFMetadataMultipleDescriptor *d;
656 
657         p->descriptor = (MXFMetadataGenericDescriptor *)
658             g_object_new (MXF_TYPE_METADATA_MULTIPLE_DESCRIPTOR, NULL);
659         d = (MXFMetadataMultipleDescriptor *) p->descriptor;
660         d->n_sub_descriptors = p->parent.n_tracks - 1;
661         d->sub_descriptors =
662             g_new0 (MXFMetadataGenericDescriptor *, p->parent.n_tracks - 1);
663 
664         mxf_uuid_init (&MXF_METADATA_BASE (d)->instance_uid, mux->metadata);
665         g_hash_table_insert (mux->metadata,
666             &MXF_METADATA_BASE (d)->instance_uid, d);
667         mux->metadata_list = g_list_prepend (mux->metadata_list, d);
668       }
669 
670       /* Tracks */
671       {
672         guint n;
673 
674         n = 1;
675 
676         /* Essence tracks */
677         for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
678           GstMXFMuxPad *pad = l->data;
679           MXFMetadataTimelineTrack *track;
680           MXFMetadataSequence *sequence;
681           MXFMetadataSourceClip *clip;
682           GstCaps *caps;
683           GstBuffer *buffer;
684 
685           p->parent.tracks[n] = (MXFMetadataTrack *)
686               g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
687           track = (MXFMetadataTimelineTrack *) p->parent.tracks[n];
688           mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
689               mux->metadata);
690           g_hash_table_insert (mux->metadata,
691               &MXF_METADATA_BASE (track)->instance_uid, track);
692           mux->metadata_list = g_list_prepend (mux->metadata_list, track);
693 
694           caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
695           buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
696           track->parent.track_id = n + 1;
697           track->parent.track_number =
698               pad->writer->get_track_number_template (pad->descriptor,
699               caps, pad->mapping_data);
700 
701           /* FIXME: All tracks in a source package must have the same edit
702            * rate! This means that if we have different edit rates, we need to
703            * make them different source packages and essence containers with
704            * a different BodySID */
705           pad->writer->get_edit_rate (pad->descriptor,
706               caps, pad->mapping_data, buffer, p, track, &track->edit_rate);
707           if (buffer)
708             gst_buffer_unref (buffer);
709           gst_caps_unref (caps);
710 
711           sequence = track->parent.sequence = (MXFMetadataSequence *)
712               g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
713           mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
714               mux->metadata);
715           g_hash_table_insert (mux->metadata,
716               &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
717           mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
718 
719           memcpy (&sequence->data_definition, &pad->writer->data_definition,
720               16);
721 
722           sequence->n_structural_components = 1;
723           sequence->structural_components =
724               g_new0 (MXFMetadataStructuralComponent *, 1);
725 
726           clip = (MXFMetadataSourceClip *)
727               g_object_new (MXF_TYPE_METADATA_SOURCE_CLIP, NULL);
728           sequence->structural_components[0] =
729               (MXFMetadataStructuralComponent *) clip;
730           mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
731               mux->metadata);
732           g_hash_table_insert (mux->metadata,
733               &MXF_METADATA_BASE (clip)->instance_uid, clip);
734           mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
735 
736           memcpy (&clip->parent.data_definition, &sequence->data_definition,
737               16);
738           clip->start_position = 0;
739 
740           pad->source_package = p;
741           pad->source_track = track;
742           pad->descriptor->linked_track_id = n + 1;
743           if (p->parent.n_tracks == 2) {
744             p->descriptor = (MXFMetadataGenericDescriptor *) pad->descriptor;
745           } else {
746             MXF_METADATA_MULTIPLE_DESCRIPTOR (p->
747                 descriptor)->sub_descriptors[n - 1] =
748                 (MXFMetadataGenericDescriptor *) pad->descriptor;
749           }
750 
751           n++;
752         }
753       }
754     }
755 
756     /* Material package */
757     {
758       MXFMetadataMaterialPackage *p;
759       MXFFraction min_edit_rate = { 0, 0 };
760       gdouble min_edit_rate_d = G_MAXDOUBLE;
761 
762       cstorage->packages[0] = (MXFMetadataGenericPackage *)
763           g_object_new (MXF_TYPE_METADATA_MATERIAL_PACKAGE, NULL);
764       memcpy (&MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
765           &mux->preface->primary_package_uid, 16);
766       g_hash_table_insert (mux->metadata,
767           &MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
768           cstorage->packages[0]);
769       mux->metadata_list =
770           g_list_prepend (mux->metadata_list, cstorage->packages[0]);
771       p = (MXFMetadataMaterialPackage *) cstorage->packages[0];
772 
773       mxf_umid_init (&p->package_uid);
774       p->name = g_strdup ("Material package");
775       memcpy (&p->package_creation_date, &mux->preface->last_modified_date,
776           sizeof (MXFTimestamp));
777       memcpy (&p->package_modified_date, &mux->preface->last_modified_date,
778           sizeof (MXFTimestamp));
779 
780       p->n_tracks = GST_ELEMENT_CAST (mux)->numsinkpads + 1;
781       p->tracks = g_new0 (MXFMetadataTrack *, p->n_tracks);
782 
783       /* Tracks */
784       {
785         guint n;
786 
787         n = 1;
788         /* Essence tracks */
789         for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
790           GstMXFMuxPad *pad = l->data;
791           GstCaps *caps;
792           GstBuffer *buffer;
793           MXFMetadataSourcePackage *source_package;
794           MXFMetadataTimelineTrack *track, *source_track;
795           MXFMetadataSequence *sequence;
796           MXFMetadataSourceClip *clip;
797 
798           source_package = MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
799           source_track =
800               MXF_METADATA_TIMELINE_TRACK (source_package->parent.tracks[n]);
801 
802           p->tracks[n] = (MXFMetadataTrack *)
803               g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
804           track = (MXFMetadataTimelineTrack *) p->tracks[n];
805           mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
806               mux->metadata);
807           g_hash_table_insert (mux->metadata,
808               &MXF_METADATA_BASE (track)->instance_uid, track);
809           mux->metadata_list = g_list_prepend (mux->metadata_list, track);
810 
811           track->parent.track_id = n + 1;
812           track->parent.track_number = 0;
813 
814           caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
815           buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
816           pad->writer->get_edit_rate (pad->descriptor,
817               caps, pad->mapping_data,
818               buffer, source_package, source_track, &track->edit_rate);
819           if (buffer)
820             gst_buffer_unref (buffer);
821           gst_caps_unref (caps);
822 
823           if (track->edit_rate.n != source_track->edit_rate.n ||
824               track->edit_rate.d != source_track->edit_rate.d) {
825             memcpy (&source_track->edit_rate, &track->edit_rate,
826                 sizeof (MXFFraction));
827           }
828 
829           if (track->edit_rate.d <= 0 || track->edit_rate.n <= 0) {
830             GST_ERROR_OBJECT (mux, "Invalid edit rate");
831             GST_OBJECT_UNLOCK (mux);
832             return GST_FLOW_ERROR;
833           }
834 
835           if (min_edit_rate_d >
836               ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d)) {
837             min_edit_rate_d =
838                 ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d);
839             memcpy (&min_edit_rate, &track->edit_rate, sizeof (MXFFraction));
840           }
841 
842           sequence = track->parent.sequence = (MXFMetadataSequence *)
843               g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
844           mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
845               mux->metadata);
846           g_hash_table_insert (mux->metadata,
847               &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
848           mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
849 
850           memcpy (&sequence->data_definition, &pad->writer->data_definition,
851               16);
852           sequence->n_structural_components = 1;
853           sequence->structural_components =
854               g_new0 (MXFMetadataStructuralComponent *, 1);
855 
856           clip = (MXFMetadataSourceClip *)
857               g_object_new (MXF_TYPE_METADATA_SOURCE_CLIP, NULL);
858           sequence->structural_components[0] =
859               (MXFMetadataStructuralComponent *) clip;
860           mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
861               mux->metadata);
862           g_hash_table_insert (mux->metadata,
863               &MXF_METADATA_BASE (clip)->instance_uid, clip);
864           mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
865 
866           memcpy (&clip->parent.data_definition, &sequence->data_definition,
867               16);
868           clip->start_position = 0;
869 
870           memcpy (&clip->source_package_id, &cstorage->packages[1]->package_uid,
871               32);
872           clip->source_track_id = n + 1;
873 
874           n++;
875         }
876 
877         n = 0;
878         /* Timecode track */
879         {
880           MXFMetadataTimelineTrack *track;
881           MXFMetadataSequence *sequence;
882           MXFMetadataTimecodeComponent *component;
883 
884           p->tracks[n] = (MXFMetadataTrack *)
885               g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
886           track = (MXFMetadataTimelineTrack *) p->tracks[n];
887           mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
888               mux->metadata);
889           g_hash_table_insert (mux->metadata,
890               &MXF_METADATA_BASE (track)->instance_uid, track);
891           mux->metadata_list = g_list_prepend (mux->metadata_list, track);
892 
893           track->parent.track_id = n + 1;
894           track->parent.track_number = 0;
895           track->parent.track_name = g_strdup ("Timecode track");
896           /* FIXME: Is this correct? */
897           memcpy (&track->edit_rate, &min_edit_rate, sizeof (MXFFraction));
898 
899           sequence = track->parent.sequence = (MXFMetadataSequence *)
900               g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
901           mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
902               mux->metadata);
903           g_hash_table_insert (mux->metadata,
904               &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
905           mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
906 
907           memcpy (&sequence->data_definition,
908               mxf_metadata_track_identifier_get
909               (MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE), 16);
910 
911           sequence->n_structural_components = 1;
912           sequence->structural_components =
913               g_new0 (MXFMetadataStructuralComponent *, 1);
914 
915           component = (MXFMetadataTimecodeComponent *)
916               g_object_new (MXF_TYPE_METADATA_TIMECODE_COMPONENT, NULL);
917           sequence->structural_components[0] =
918               (MXFMetadataStructuralComponent *) component;
919           mxf_uuid_init (&MXF_METADATA_BASE (component)->instance_uid,
920               mux->metadata);
921           g_hash_table_insert (mux->metadata,
922               &MXF_METADATA_BASE (component)->instance_uid, component);
923           mux->metadata_list = g_list_prepend (mux->metadata_list, component);
924 
925           memcpy (&component->parent.data_definition,
926               &sequence->data_definition, 16);
927 
928           component->start_timecode = 0;
929           if (track->edit_rate.d == 0)
930             component->rounded_timecode_base = 1;
931           else
932             component->rounded_timecode_base =
933                 (((gdouble) track->edit_rate.n) /
934                 ((gdouble) track->edit_rate.d) + 0.5);
935           /* TODO: drop frame */
936         }
937 
938         memcpy (&mux->min_edit_rate, &min_edit_rate, sizeof (MXFFraction));
939       }
940     }
941 
942     /* Timecode track */
943     {
944       MXFMetadataSourcePackage *p;
945       MXFMetadataTimelineTrack *track;
946       MXFMetadataSequence *sequence;
947       MXFMetadataTimecodeComponent *component;
948       guint n = 0;
949 
950       p = (MXFMetadataSourcePackage *) cstorage->packages[1];
951 
952       p->parent.tracks[n] = (MXFMetadataTrack *)
953           g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
954       track = (MXFMetadataTimelineTrack *) p->parent.tracks[n];
955       mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid, mux->metadata);
956       g_hash_table_insert (mux->metadata,
957           &MXF_METADATA_BASE (track)->instance_uid, track);
958       mux->metadata_list = g_list_prepend (mux->metadata_list, track);
959 
960       track->parent.track_id = n + 1;
961       track->parent.track_number = 0;
962       track->parent.track_name = g_strdup ("Timecode track");
963       /* FIXME: Is this correct? */
964       memcpy (&track->edit_rate, &mux->min_edit_rate, sizeof (MXFFraction));
965 
966       sequence = track->parent.sequence = (MXFMetadataSequence *)
967           g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
968       mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
969           mux->metadata);
970       g_hash_table_insert (mux->metadata,
971           &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
972       mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
973 
974       memcpy (&sequence->data_definition,
975           mxf_metadata_track_identifier_get
976           (MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE), 16);
977 
978       sequence->n_structural_components = 1;
979       sequence->structural_components =
980           g_new0 (MXFMetadataStructuralComponent *, 1);
981 
982       component = (MXFMetadataTimecodeComponent *)
983           g_object_new (MXF_TYPE_METADATA_TIMECODE_COMPONENT, NULL);
984       sequence->structural_components[0] =
985           (MXFMetadataStructuralComponent *) component;
986       mxf_uuid_init (&MXF_METADATA_BASE (component)->instance_uid,
987           mux->metadata);
988       g_hash_table_insert (mux->metadata,
989           &MXF_METADATA_BASE (component)->instance_uid, component);
990       mux->metadata_list = g_list_prepend (mux->metadata_list, component);
991 
992       memcpy (&component->parent.data_definition,
993           &sequence->data_definition, 16);
994 
995       component->start_timecode = 0;
996       if (track->edit_rate.d == 0)
997         component->rounded_timecode_base = 1;
998       else
999         component->rounded_timecode_base =
1000             (((gdouble) track->edit_rate.n) /
1001             ((gdouble) track->edit_rate.d) + 0.5);
1002       /* TODO: drop frame */
1003     }
1004 
1005 
1006     for (i = 1; i < cstorage->packages[1]->n_tracks; i++) {
1007       MXFMetadataTrack *track = cstorage->packages[1]->tracks[i];
1008       guint j;
1009       guint32 templ;
1010       guint8 n_type, n;
1011 
1012       if ((track->track_number & 0x00ff00ff) != 0)
1013         continue;
1014 
1015       templ = track->track_number;
1016       n_type = 0;
1017 
1018       for (j = 1; j < cstorage->packages[1]->n_tracks; j++) {
1019         MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
1020 
1021         if (tmp->track_number == templ) {
1022           n_type++;
1023         }
1024       }
1025 
1026       n = 0;
1027       for (j = 1; j < cstorage->packages[1]->n_tracks; j++) {
1028         MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
1029 
1030         if (tmp->track_number == templ) {
1031           n++;
1032           tmp->track_number |= (n_type << 16) | (n);
1033         }
1034       }
1035     }
1036 
1037     cstorage->n_essence_container_data = 1;
1038     cstorage->essence_container_data =
1039         g_new0 (MXFMetadataEssenceContainerData *, 1);
1040     cstorage->essence_container_data[0] = (MXFMetadataEssenceContainerData *)
1041         g_object_new (MXF_TYPE_METADATA_ESSENCE_CONTAINER_DATA, NULL);
1042     mxf_uuid_init (&MXF_METADATA_BASE (cstorage->essence_container_data[0])->
1043         instance_uid, mux->metadata);
1044     g_hash_table_insert (mux->metadata,
1045         &MXF_METADATA_BASE (cstorage->essence_container_data[0])->instance_uid,
1046         cstorage->essence_container_data[0]);
1047     mux->metadata_list =
1048         g_list_prepend (mux->metadata_list,
1049         cstorage->essence_container_data[0]);
1050 
1051     cstorage->essence_container_data[0]->linked_package =
1052         MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
1053     cstorage->essence_container_data[0]->index_sid = 2;
1054     cstorage->essence_container_data[0]->body_sid = 1;
1055   }
1056 
1057   /* Sort descriptors at the correct places */
1058   {
1059     GList *l;
1060     GList *descriptors = NULL;
1061 
1062     for (l = mux->metadata_list; l; l = l->next) {
1063       MXFMetadataBase *m = l->data;
1064 
1065       if (MXF_IS_METADATA_GENERIC_DESCRIPTOR (m)
1066           && !MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m)) {
1067         descriptors = l;
1068         l->prev->next = NULL;
1069         l->prev = NULL;
1070         break;
1071       }
1072     }
1073 
1074     g_assert (descriptors != NULL);
1075 
1076     for (l = mux->metadata_list; l; l = l->next) {
1077       MXFMetadataBase *m = l->data;
1078       GList *s;
1079 
1080       if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m) ||
1081           MXF_IS_METADATA_SOURCE_PACKAGE (m)) {
1082         s = l->prev;
1083         l->prev = g_list_last (descriptors);
1084         s->next = descriptors;
1085         descriptors->prev = s;
1086         l->prev->next = l;
1087         break;
1088       }
1089     }
1090   }
1091 
1092   GST_OBJECT_UNLOCK (mux);
1093 
1094   mux->metadata_list = g_list_reverse (mux->metadata_list);
1095 
1096   return ret;
1097 }
1098 
1099 static GstFlowReturn
gst_mxf_mux_init_partition_pack(GstMXFMux * mux)1100 gst_mxf_mux_init_partition_pack (GstMXFMux * mux)
1101 {
1102   GList *l;
1103   guint i = 0;
1104 
1105   mxf_partition_pack_reset (&mux->partition);
1106   mux->partition.type = MXF_PARTITION_PACK_HEADER;
1107   mux->partition.closed = mux->partition.complete = FALSE;
1108   mux->partition.major_version = 0x0001;
1109   mux->partition.minor_version = 0x0002;
1110   mux->partition.kag_size = 1;
1111   mux->partition.this_partition = 0;
1112   mux->partition.prev_partition = 0;
1113   mux->partition.footer_partition = 0;
1114   mux->partition.header_byte_count = 0;
1115   mux->partition.index_byte_count = 0;
1116   mux->partition.index_sid = 0;
1117   mux->partition.body_offset = 0;
1118   mux->partition.body_sid = 0;
1119 
1120   memcpy (&mux->partition.operational_pattern,
1121       &mux->preface->operational_pattern, 16);
1122 
1123   GST_OBJECT_LOCK (mux);
1124   mux->partition.n_essence_containers = GST_ELEMENT_CAST (mux)->numsinkpads;
1125   mux->partition.essence_containers =
1126       g_new0 (MXFUL, mux->partition.n_essence_containers);
1127 
1128   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1129     GstMXFMuxPad *pad = l->data;
1130     guint j;
1131     gboolean found = FALSE;
1132 
1133     for (j = 0; j <= i; j++) {
1134       if (mxf_ul_is_equal (&pad->descriptor->essence_container,
1135               &mux->partition.essence_containers[j])) {
1136         found = TRUE;
1137         break;
1138       }
1139     }
1140 
1141     if (found)
1142       continue;
1143 
1144     memcpy (&mux->partition.essence_containers[i],
1145         &pad->descriptor->essence_container, 16);
1146     i++;
1147   }
1148   mux->partition.n_essence_containers = i;
1149   GST_OBJECT_UNLOCK (mux);
1150 
1151   return GST_FLOW_OK;
1152 }
1153 
1154 static GstFlowReturn
gst_mxf_mux_write_header_metadata(GstMXFMux * mux)1155 gst_mxf_mux_write_header_metadata (GstMXFMux * mux)
1156 {
1157   GstFlowReturn ret = GST_FLOW_OK;
1158   GstBuffer *buf;
1159   GList *buffers = NULL;
1160   GList *l;
1161   MXFMetadataBase *m;
1162   guint64 header_byte_count = 0;
1163 
1164   for (l = mux->metadata_list; l; l = l->next) {
1165     m = l->data;
1166     buf = mxf_metadata_base_to_buffer (m, &mux->primer);
1167     header_byte_count += gst_buffer_get_size (buf);
1168     buffers = g_list_prepend (buffers, buf);
1169   }
1170 
1171   buffers = g_list_reverse (buffers);
1172   buf = mxf_primer_pack_to_buffer (&mux->primer);
1173   header_byte_count += gst_buffer_get_size (buf);
1174   buffers = g_list_prepend (buffers, buf);
1175 
1176   mux->partition.header_byte_count = header_byte_count;
1177   buf = mxf_partition_pack_to_buffer (&mux->partition);
1178   if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1179     GST_ERROR_OBJECT (mux, "Failed pushing partition: %s",
1180         gst_flow_get_name (ret));
1181     g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
1182     g_list_free (buffers);
1183     return ret;
1184   }
1185 
1186   for (l = buffers; l; l = l->next) {
1187     buf = l->data;
1188     l->data = NULL;
1189     if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1190       GST_ERROR_OBJECT (mux, "Failed pushing buffer: %s",
1191           gst_flow_get_name (ret));
1192       g_list_foreach (l, (GFunc) gst_mini_object_unref, NULL);
1193       g_list_free (buffers);
1194       return ret;
1195     }
1196   }
1197 
1198   g_list_free (buffers);
1199 
1200   return ret;
1201 }
1202 
1203 static const guint8 _gc_essence_element_ul[] = {
1204   0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
1205   0x0d, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00
1206 };
1207 
1208 static GstFlowReturn
gst_mxf_mux_handle_buffer(GstMXFMux * mux,GstMXFMuxPad * pad)1209 gst_mxf_mux_handle_buffer (GstMXFMux * mux, GstMXFMuxPad * pad)
1210 {
1211   GstBuffer *buf = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
1212   GstBuffer *outbuf = NULL;
1213   GstMapInfo map;
1214   gsize buf_size;
1215   GstFlowReturn ret = GST_FLOW_OK;
1216   guint8 slen, ber[9];
1217   gboolean flush = gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))
1218       && !pad->have_complete_edit_unit && buf == NULL;
1219   gboolean is_keyframe = buf ?
1220       !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) : TRUE;
1221   GstClockTime pts = buf ? GST_BUFFER_PTS (buf) : GST_CLOCK_TIME_NONE;
1222   GstClockTime dts = buf ? GST_BUFFER_DTS (buf) : GST_CLOCK_TIME_NONE;
1223 
1224   if (pad->have_complete_edit_unit) {
1225     GST_DEBUG_OBJECT (pad,
1226         "Handling remaining buffer for track %u at position %" G_GINT64_FORMAT,
1227         pad->source_track->parent.track_id, pad->pos);
1228     if (buf)
1229       gst_buffer_unref (buf);
1230     buf = NULL;
1231   } else if (!flush) {
1232     if (buf)
1233       gst_buffer_unref (buf);
1234     buf = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (pad));
1235   }
1236 
1237   if (buf) {
1238     GST_DEBUG_OBJECT (pad,
1239         "Handling buffer of size %" G_GSIZE_FORMAT " for track %u at position %"
1240         G_GINT64_FORMAT, gst_buffer_get_size (buf),
1241         pad->source_track->parent.track_id, pad->pos);
1242   } else {
1243     flush = TRUE;
1244     GST_DEBUG_OBJECT (pad,
1245         "Flushing for track %u at position %" G_GINT64_FORMAT,
1246         pad->source_track->parent.track_id, pad->pos);
1247   }
1248 
1249   ret = pad->write_func (buf, pad->mapping_data, pad->adapter, &outbuf, flush);
1250   if (ret != GST_FLOW_OK && ret != GST_FLOW_CUSTOM_SUCCESS) {
1251     GST_ERROR_OBJECT (pad,
1252         "Failed handling buffer for track %u, reason %s",
1253         pad->source_track->parent.track_id, gst_flow_get_name (ret));
1254     return ret;
1255   }
1256 
1257   if (ret == GST_FLOW_CUSTOM_SUCCESS) {
1258     pad->have_complete_edit_unit = TRUE;
1259     ret = GST_FLOW_OK;
1260   } else {
1261     pad->have_complete_edit_unit = FALSE;
1262   }
1263 
1264   buf = outbuf;
1265   if (buf == NULL)
1266     return ret;
1267 
1268   /* We currently only index the first essence stream */
1269   if (pad == (GstMXFMuxPad *) GST_ELEMENT_CAST (mux)->sinkpads->data) {
1270     MXFIndexTableSegment *segment;
1271     const gint max_segment_size = G_MAXUINT16 / 11;
1272 
1273     if (mux->index_table->len == 0 ||
1274         g_array_index (mux->index_table, MXFIndexTableSegment,
1275             mux->current_index_pos).index_duration >= max_segment_size) {
1276 
1277       if (mux->index_table->len > 0)
1278         mux->current_index_pos++;
1279 
1280       if (mux->index_table->len <= mux->current_index_pos) {
1281         MXFIndexTableSegment s;
1282 
1283         memset (&segment, 0, sizeof (segment));
1284 
1285         mxf_uuid_init (&s.instance_id, mux->metadata);
1286         memcpy (&s.index_edit_rate, &pad->source_track->edit_rate,
1287             sizeof (s.index_edit_rate));
1288         if (mux->index_table->len > 0)
1289           s.index_start_position =
1290               g_array_index (mux->index_table, MXFIndexTableSegment,
1291               mux->index_table->len - 1).index_start_position;
1292         else
1293           s.index_start_position = 0;
1294         s.index_duration = 0;
1295         s.edit_unit_byte_count = 0;
1296         s.index_sid =
1297             mux->preface->content_storage->essence_container_data[0]->index_sid;
1298         s.body_sid =
1299             mux->preface->content_storage->essence_container_data[0]->body_sid;
1300         s.slice_count = 0;
1301         s.pos_table_count = 0;
1302         s.n_delta_entries = 0;
1303         s.delta_entries = NULL;
1304         s.n_index_entries = 0;
1305         s.index_entries = g_new0 (MXFIndexEntry, max_segment_size);
1306         g_array_append_val (mux->index_table, s);
1307       }
1308     }
1309     segment =
1310         &g_array_index (mux->index_table, MXFIndexTableSegment,
1311         mux->current_index_pos);
1312 
1313     if (dts != GST_CLOCK_TIME_NONE && pts != GST_CLOCK_TIME_NONE) {
1314       guint64 pts_pos;
1315       guint64 pts_index_pos, pts_segment_pos;
1316       gint64 index_pos_diff;
1317       MXFIndexTableSegment *pts_segment;
1318 
1319       pts =
1320           gst_segment_to_running_time (&pad->parent.segment, GST_FORMAT_TIME,
1321           pts);
1322       pts_pos =
1323           gst_util_uint64_scale_round (pts, pad->source_track->edit_rate.n,
1324           pad->source_track->edit_rate.d * GST_SECOND);
1325 
1326       index_pos_diff = pts_pos - pad->pos;
1327       pts_index_pos = mux->current_index_pos;
1328       pts_segment_pos = segment->n_index_entries;
1329       if (index_pos_diff >= 0) {
1330         while (pts_segment_pos + index_pos_diff >= max_segment_size) {
1331           index_pos_diff -= max_segment_size - pts_segment_pos;
1332           pts_segment_pos = 0;
1333           pts_index_pos++;
1334 
1335           if (pts_index_pos >= mux->index_table->len) {
1336             MXFIndexTableSegment s;
1337 
1338             memset (&segment, 0, sizeof (segment));
1339 
1340             mxf_uuid_init (&s.instance_id, mux->metadata);
1341             memcpy (&s.index_edit_rate, &pad->source_track->edit_rate,
1342                 sizeof (s.index_edit_rate));
1343             if (mux->index_table->len > 0)
1344               s.index_start_position =
1345                   g_array_index (mux->index_table, MXFIndexTableSegment,
1346                   mux->index_table->len - 1).index_start_position;
1347             else
1348               s.index_start_position = 0;
1349             s.index_duration = 0;
1350             s.edit_unit_byte_count = 0;
1351             s.index_sid =
1352                 mux->preface->content_storage->
1353                 essence_container_data[0]->index_sid;
1354             s.body_sid =
1355                 mux->preface->content_storage->
1356                 essence_container_data[0]->body_sid;
1357             s.slice_count = 0;
1358             s.pos_table_count = 0;
1359             s.n_delta_entries = 0;
1360             s.delta_entries = NULL;
1361             s.n_index_entries = 0;
1362             s.index_entries = g_new0 (MXFIndexEntry, max_segment_size);
1363             g_array_append_val (mux->index_table, s);
1364           }
1365         }
1366       } else {
1367         while (pts_segment_pos + index_pos_diff <= 0) {
1368           if (pts_index_pos == 0) {
1369             pts_index_pos = G_MAXUINT64;
1370             break;
1371           }
1372           index_pos_diff += pts_segment_pos;
1373           pts_segment_pos = max_segment_size;
1374           pts_index_pos--;
1375         }
1376       }
1377       if (pts_index_pos != G_MAXUINT64) {
1378         g_assert (index_pos_diff < 127 && index_pos_diff >= -127);
1379         pts_segment =
1380             &g_array_index (mux->index_table, MXFIndexTableSegment,
1381             pts_index_pos);
1382         pts_segment->index_entries[pts_segment_pos +
1383             index_pos_diff].temporal_offset = -index_pos_diff;
1384       }
1385     }
1386 
1387     /* Leave temporal offset initialized at 0, above code will set it as necessary */
1388     ;
1389     if (is_keyframe)
1390       mux->last_keyframe_pos = pad->pos;
1391     segment->index_entries[segment->n_index_entries].key_frame_offset =
1392         MIN (pad->pos - mux->last_keyframe_pos, 127);
1393     segment->index_entries[segment->n_index_entries].flags = is_keyframe ? 0x80 : 0x20; /* FIXME: Need to distinguish all the cases */
1394     segment->index_entries[segment->n_index_entries].stream_offset =
1395         mux->partition.body_offset;
1396 
1397     segment->n_index_entries++;
1398     segment->index_duration++;
1399   }
1400 
1401   buf_size = gst_buffer_get_size (buf);
1402   slen = mxf_ber_encode_size (buf_size, ber);
1403   outbuf = gst_buffer_new_and_alloc (16 + slen);
1404   gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1405   memcpy (map.data, _gc_essence_element_ul, 16);
1406   GST_WRITE_UINT32_BE (map.data + 12, pad->source_track->parent.track_number);
1407   memcpy (map.data + 16, ber, slen);
1408   gst_buffer_unmap (outbuf, &map);
1409   outbuf = gst_buffer_append (outbuf, buf);
1410 
1411   GST_DEBUG_OBJECT (pad,
1412       "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u",
1413       gst_buffer_get_size (outbuf), pad->source_track->parent.track_id);
1414 
1415   mux->partition.body_offset += gst_buffer_get_size (outbuf);
1416   if ((ret = gst_mxf_mux_push (mux, outbuf)) != GST_FLOW_OK) {
1417     GST_ERROR_OBJECT (pad,
1418         "Failed pushing buffer for track %u, reason %s",
1419         pad->source_track->parent.track_id, gst_flow_get_name (ret));
1420     return ret;
1421   }
1422 
1423   pad->pos++;
1424   pad->last_timestamp =
1425       gst_util_uint64_scale (GST_SECOND * pad->pos,
1426       pad->source_track->edit_rate.d, pad->source_track->edit_rate.n);
1427 
1428   return ret;
1429 }
1430 
1431 static GstFlowReturn
gst_mxf_mux_write_body_partition(GstMXFMux * mux)1432 gst_mxf_mux_write_body_partition (GstMXFMux * mux)
1433 {
1434   GstBuffer *buf;
1435 
1436   mux->partition.type = MXF_PARTITION_PACK_BODY;
1437   mux->partition.closed = TRUE;
1438   mux->partition.complete = TRUE;
1439   mux->partition.this_partition = mux->offset;
1440   mux->partition.prev_partition = 0;
1441   mux->partition.footer_partition = 0;
1442   mux->partition.header_byte_count = 0;
1443   mux->partition.index_byte_count = 0;
1444   mux->partition.index_sid = 0;
1445   mux->partition.body_offset = 0;
1446   mux->partition.body_sid =
1447       mux->preface->content_storage->essence_container_data[0]->body_sid;
1448 
1449   buf = mxf_partition_pack_to_buffer (&mux->partition);
1450   return gst_mxf_mux_push (mux, buf);
1451 }
1452 
1453 static GstFlowReturn
gst_mxf_mux_handle_eos(GstMXFMux * mux)1454 gst_mxf_mux_handle_eos (GstMXFMux * mux)
1455 {
1456   GList *l;
1457   gboolean have_data = FALSE;
1458   GstBuffer *packet;
1459 
1460   do {
1461     GstMXFMuxPad *best = NULL;
1462 
1463     have_data = FALSE;
1464 
1465     GST_OBJECT_LOCK (mux);
1466     for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1467       GstMXFMuxPad *pad = l->data;
1468       GstBuffer *buffer =
1469           gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
1470 
1471       GstClockTime next_gc_timestamp =
1472           gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1473           mux->min_edit_rate.d, mux->min_edit_rate.n);
1474 
1475       if (pad->have_complete_edit_unit ||
1476           gst_adapter_available (pad->adapter) > 0 || buffer) {
1477         have_data = TRUE;
1478         if (pad->last_timestamp < next_gc_timestamp) {
1479           best = gst_object_ref (pad);
1480           if (buffer)
1481             gst_buffer_unref (buffer);
1482           break;
1483         }
1484       }
1485       if (buffer)
1486         gst_buffer_unref (buffer);
1487 
1488       if (have_data && !l->next) {
1489         mux->last_gc_position++;
1490         mux->last_gc_timestamp = next_gc_timestamp;
1491         break;
1492       }
1493     }
1494     GST_OBJECT_UNLOCK (mux);
1495 
1496     if (best) {
1497       gst_mxf_mux_handle_buffer (mux, best);
1498       gst_object_unref (best);
1499       have_data = TRUE;
1500     }
1501   } while (have_data);
1502 
1503   mux->last_gc_position++;
1504   mux->last_gc_timestamp =
1505       gst_util_uint64_scale (mux->last_gc_position * GST_SECOND,
1506       mux->min_edit_rate.d, mux->min_edit_rate.n);
1507 
1508   /* Update essence track durations */
1509   GST_OBJECT_LOCK (mux);
1510   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1511     GstMXFMuxPad *pad = l->data;
1512     guint i;
1513 
1514     /* Update durations */
1515     pad->source_track->parent.sequence->duration = pad->pos;
1516     MXF_METADATA_SOURCE_CLIP (pad->source_track->parent.
1517         sequence->structural_components[0])->parent.duration = pad->pos;
1518     for (i = 0; i < mux->preface->content_storage->packages[0]->n_tracks; i++) {
1519       MXFMetadataTimelineTrack *track;
1520 
1521       if (!MXF_IS_METADATA_TIMELINE_TRACK (mux->preface->
1522               content_storage->packages[0]->tracks[i])
1523           || !MXF_IS_METADATA_SOURCE_CLIP (mux->preface->
1524               content_storage->packages[0]->tracks[i]->sequence->
1525               structural_components[0]))
1526         continue;
1527 
1528       track =
1529           MXF_METADATA_TIMELINE_TRACK (mux->preface->
1530           content_storage->packages[0]->tracks[i]);
1531       if (MXF_METADATA_SOURCE_CLIP (track->parent.
1532               sequence->structural_components[0])->source_track_id ==
1533           pad->source_track->parent.track_id) {
1534         track->parent.sequence->structural_components[0]->duration = pad->pos;
1535         track->parent.sequence->duration = pad->pos;
1536       }
1537     }
1538   }
1539   GST_OBJECT_UNLOCK (mux);
1540 
1541   /* Update timecode track duration */
1542   {
1543     MXFMetadataTimelineTrack *track =
1544         MXF_METADATA_TIMELINE_TRACK (mux->preface->
1545         content_storage->packages[0]->tracks[0]);
1546     MXFMetadataSequence *sequence = track->parent.sequence;
1547     MXFMetadataTimecodeComponent *component =
1548         MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1549 
1550     sequence->duration = mux->last_gc_position;
1551     component->parent.duration = mux->last_gc_position;
1552   }
1553 
1554   {
1555     MXFMetadataTimelineTrack *track =
1556         MXF_METADATA_TIMELINE_TRACK (mux->preface->
1557         content_storage->packages[1]->tracks[0]);
1558     MXFMetadataSequence *sequence = track->parent.sequence;
1559     MXFMetadataTimecodeComponent *component =
1560         MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1561 
1562     sequence->duration = mux->last_gc_position;
1563     component->parent.duration = mux->last_gc_position;
1564   }
1565 
1566   {
1567     guint64 body_partition = mux->partition.this_partition;
1568     guint32 body_sid = mux->partition.body_sid;
1569     guint64 footer_partition = mux->offset;
1570     GArray *rip;
1571     GstFlowReturn ret;
1572     GstSegment segment;
1573     MXFRandomIndexPackEntry entry;
1574     GList *index_entries = NULL, *l;
1575     guint index_byte_count = 0;
1576     guint i;
1577     GstBuffer *buf;
1578 
1579     for (i = 0; i < mux->index_table->len; i++) {
1580       MXFIndexTableSegment *segment =
1581           &g_array_index (mux->index_table, MXFIndexTableSegment, i);
1582       GstBuffer *segment_buffer = mxf_index_table_segment_to_buffer (segment);
1583 
1584       index_byte_count += gst_buffer_get_size (segment_buffer);
1585       index_entries = g_list_prepend (index_entries, segment_buffer);
1586     }
1587 
1588     mux->partition.type = MXF_PARTITION_PACK_FOOTER;
1589     mux->partition.closed = TRUE;
1590     mux->partition.complete = TRUE;
1591     mux->partition.this_partition = mux->offset;
1592     mux->partition.prev_partition = body_partition;
1593     mux->partition.footer_partition = mux->offset;
1594     mux->partition.header_byte_count = 0;
1595     mux->partition.index_byte_count = index_byte_count;
1596     mux->partition.index_sid =
1597         mux->preface->content_storage->essence_container_data[0]->index_sid;
1598     mux->partition.body_offset = 0;
1599     mux->partition.body_sid = 0;
1600 
1601     gst_mxf_mux_write_header_metadata (mux);
1602 
1603     index_entries = g_list_reverse (index_entries);
1604     for (l = index_entries; l; l = l->next) {
1605       if ((ret = gst_mxf_mux_push (mux, l->data)) != GST_FLOW_OK) {
1606         GST_ERROR_OBJECT (mux, "Failed pushing index table segment");
1607       }
1608     }
1609     g_list_free (index_entries);
1610 
1611     rip = g_array_sized_new (FALSE, FALSE, sizeof (MXFRandomIndexPackEntry), 3);
1612     entry.offset = 0;
1613     entry.body_sid = 0;
1614     g_array_append_val (rip, entry);
1615     entry.offset = body_partition;
1616     entry.body_sid = body_sid;
1617     g_array_append_val (rip, entry);
1618     entry.offset = footer_partition;
1619     entry.body_sid = 0;
1620     g_array_append_val (rip, entry);
1621 
1622     packet = mxf_random_index_pack_to_buffer (rip);
1623     if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
1624       GST_ERROR_OBJECT (mux, "Failed pushing random index pack");
1625     }
1626     g_array_free (rip, TRUE);
1627 
1628     /* Rewrite header partition with updated values */
1629     gst_segment_init (&segment, GST_FORMAT_BYTES);
1630     if (gst_pad_push_event (GST_AGGREGATOR_SRC_PAD (mux),
1631             gst_event_new_segment (&segment))) {
1632       mux->offset = 0;
1633       mux->partition.type = MXF_PARTITION_PACK_HEADER;
1634       mux->partition.closed = TRUE;
1635       mux->partition.complete = TRUE;
1636       mux->partition.this_partition = 0;
1637       mux->partition.prev_partition = 0;
1638       mux->partition.footer_partition = footer_partition;
1639       mux->partition.header_byte_count = 0;
1640       mux->partition.index_byte_count = 0;
1641       mux->partition.index_sid = 0;
1642       mux->partition.body_offset = 0;
1643       mux->partition.body_sid = 0;
1644 
1645       ret = gst_mxf_mux_write_header_metadata (mux);
1646       if (ret != GST_FLOW_OK) {
1647         GST_ERROR_OBJECT (mux, "Rewriting header partition failed");
1648         return ret;
1649       }
1650 
1651       g_assert (mux->offset == body_partition);
1652 
1653       mux->partition.type = MXF_PARTITION_PACK_BODY;
1654       mux->partition.closed = TRUE;
1655       mux->partition.complete = TRUE;
1656       mux->partition.this_partition = mux->offset;
1657       mux->partition.prev_partition = 0;
1658       mux->partition.footer_partition = footer_partition;
1659       mux->partition.header_byte_count = 0;
1660       mux->partition.index_byte_count = 0;
1661       mux->partition.index_sid = 0;
1662       mux->partition.body_offset = 0;
1663       mux->partition.body_sid =
1664           mux->preface->content_storage->essence_container_data[0]->body_sid;
1665 
1666       buf = mxf_partition_pack_to_buffer (&mux->partition);
1667       ret = gst_mxf_mux_push (mux, buf);
1668       if (ret != GST_FLOW_OK) {
1669         GST_ERROR_OBJECT (mux, "Rewriting body partition failed");
1670         return ret;
1671       }
1672     } else {
1673       GST_WARNING_OBJECT (mux, "Can't rewrite header partition");
1674     }
1675   }
1676 
1677   return GST_FLOW_OK;
1678 }
1679 
1680 static gint
_sort_mux_pads(gconstpointer a,gconstpointer b)1681 _sort_mux_pads (gconstpointer a, gconstpointer b)
1682 {
1683   const GstMXFMuxPad *pa = a, *pb = b;
1684   MXFMetadataTrackType ta =
1685       mxf_metadata_track_identifier_parse (&pa->writer->data_definition);
1686   MXFMetadataTrackType tb =
1687       mxf_metadata_track_identifier_parse (&pb->writer->data_definition);
1688 
1689   if (ta != tb)
1690     return ta - tb;
1691 
1692   return pa->source_track->parent.track_number -
1693       pa->source_track->parent.track_number;
1694 }
1695 
1696 
1697 static gboolean
gst_mxf_mux_stop(GstAggregator * aggregator)1698 gst_mxf_mux_stop (GstAggregator * aggregator)
1699 {
1700   GstMXFMux *mux = GST_MXF_MUX (aggregator);
1701 
1702   gst_mxf_mux_reset (mux);
1703 
1704   return TRUE;
1705 }
1706 
1707 static GstFlowReturn
gst_mxf_mux_aggregate(GstAggregator * aggregator,gboolean timeout)1708 gst_mxf_mux_aggregate (GstAggregator * aggregator, gboolean timeout)
1709 {
1710   GstMXFMux *mux = GST_MXF_MUX (aggregator);
1711   GstMXFMuxPad *best = NULL;
1712   GstFlowReturn ret;
1713   GList *l;
1714   gboolean eos = TRUE;
1715 
1716   if (timeout) {
1717     GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1718         ("Live mixing and got a timeout. This is not supported yet"));
1719     ret = GST_FLOW_ERROR;
1720     goto error;
1721   }
1722 
1723   if (mux->state == GST_MXF_MUX_STATE_ERROR) {
1724     GST_ERROR_OBJECT (mux, "Had an error before -- returning");
1725     return GST_FLOW_ERROR;
1726   } else if (mux->state == GST_MXF_MUX_STATE_EOS) {
1727     GST_WARNING_OBJECT (mux, "EOS");
1728     return GST_FLOW_EOS;
1729   }
1730 
1731   if (mux->state == GST_MXF_MUX_STATE_HEADER) {
1732     GstCaps *caps;
1733 
1734     if (GST_ELEMENT_CAST (mux)->sinkpads == NULL) {
1735       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1736           ("No input streams configured"));
1737       ret = GST_FLOW_ERROR;
1738       goto error;
1739     }
1740 
1741     caps = gst_caps_new_empty_simple ("application/mxf");
1742     gst_aggregator_set_src_caps (GST_AGGREGATOR (mux), caps);
1743     gst_caps_unref (caps);
1744 
1745     if ((ret = gst_mxf_mux_create_metadata (mux)) != GST_FLOW_OK)
1746       goto error;
1747 
1748     if ((ret = gst_mxf_mux_init_partition_pack (mux)) != GST_FLOW_OK)
1749       goto error;
1750 
1751     if ((ret = gst_mxf_mux_write_header_metadata (mux)) != GST_FLOW_OK)
1752       goto error;
1753 
1754     /* Sort pads, we will always write in that order */
1755     GST_OBJECT_LOCK (mux);
1756     GST_ELEMENT_CAST (mux)->sinkpads =
1757         g_list_sort (GST_ELEMENT_CAST (mux)->sinkpads, _sort_mux_pads);
1758     GST_OBJECT_UNLOCK (mux);
1759 
1760     /* Write body partition */
1761     ret = gst_mxf_mux_write_body_partition (mux);
1762     if (ret != GST_FLOW_OK)
1763       goto error;
1764     mux->state = GST_MXF_MUX_STATE_DATA;
1765   }
1766 
1767   g_return_val_if_fail (g_hash_table_size (mux->metadata) > 0, GST_FLOW_ERROR);
1768 
1769   do {
1770     GST_OBJECT_LOCK (mux);
1771     for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1772       gboolean pad_eos;
1773       GstMXFMuxPad *pad = l->data;
1774       GstBuffer *buffer;
1775       GstClockTime next_gc_timestamp =
1776           gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1777           mux->min_edit_rate.d, mux->min_edit_rate.n);
1778 
1779       pad_eos = gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad));
1780       if (!pad_eos)
1781         eos = FALSE;
1782 
1783       buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
1784 
1785       if ((!pad_eos || pad->have_complete_edit_unit ||
1786               gst_adapter_available (pad->adapter) > 0 || buffer)
1787           && pad->last_timestamp < next_gc_timestamp) {
1788         if (buffer)
1789           gst_buffer_unref (buffer);
1790         best = gst_object_ref (pad);
1791         break;
1792       } else if (!eos && !l->next) {
1793         mux->last_gc_position++;
1794         mux->last_gc_timestamp = next_gc_timestamp;
1795         eos = FALSE;
1796         if (buffer)
1797           gst_buffer_unref (buffer);
1798         best = NULL;
1799         break;
1800       }
1801       if (buffer)
1802         gst_buffer_unref (buffer);
1803     }
1804     GST_OBJECT_UNLOCK (mux);
1805   } while (!eos && best == NULL);
1806 
1807   if (!eos && best) {
1808     ret = gst_mxf_mux_handle_buffer (mux, best);
1809     gst_object_unref (best);
1810     if (ret != GST_FLOW_OK)
1811       goto error;
1812   } else if (eos) {
1813     GST_DEBUG_OBJECT (mux, "Handling EOS");
1814 
1815     if (best)
1816       gst_object_unref (best);
1817 
1818     gst_mxf_mux_handle_eos (mux);
1819     mux->state = GST_MXF_MUX_STATE_EOS;
1820     return GST_FLOW_EOS;
1821   } else {
1822     g_assert_not_reached ();
1823   }
1824 
1825   return GST_FLOW_OK;
1826 
1827 error:
1828   {
1829     mux->state = GST_MXF_MUX_STATE_ERROR;
1830     return ret;
1831   }
1832 }
1833