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