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, µ, &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