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