2 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
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.
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.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-mxfmux
23 * mxfmux muxes different streams into an MXF file.
26 * <title>Example launch line</title>
28 * gst-launch -v filesrc location=/path/to/audio ! decodebin2 ! queue ! mxfmux name=m ! filesink location=file.mxf filesrc location=/path/to/video ! decodebin2 ! queue ! m.
29 * ]| This pipeline muxes an audio and video file into a single MXF file.
42 #ifdef HAVE_SYS_UTSNAME_H
43 #include <sys/utsname.h>
46 GST_DEBUG_CATEGORY_STATIC (mxfmux_debug);
47 #define GST_CAT_DEFAULT mxfmux_debug
49 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
52 GST_STATIC_CAPS ("application/mxf")
60 GST_BOILERPLATE (GstMXFMux, gst_mxf_mux, GstElement, GST_TYPE_ELEMENT);
62 static void gst_mxf_mux_finalize (GObject * object);
63 static void gst_mxf_mux_set_property (GObject * object,
64 guint prop_id, const GValue * value, GParamSpec * pspec);
65 static void gst_mxf_mux_get_property (GObject * object,
66 guint prop_id, GValue * value, GParamSpec * pspec);
68 static GstFlowReturn gst_mxf_mux_collected (GstCollectPads * pads,
71 static gboolean gst_mxf_mux_handle_src_event (GstPad * pad, GstEvent * event);
72 static GstPad *gst_mxf_mux_request_new_pad (GstElement * element,
73 GstPadTemplate * templ, const gchar * name);
74 static void gst_mxf_mux_release_pad (GstElement * element, GstPad * pad);
76 static GstStateChangeReturn
77 gst_mxf_mux_change_state (GstElement * element, GstStateChange transition);
79 static void gst_mxf_mux_reset (GstMXFMux * mux);
82 gst_mxf_mux_push (GstMXFMux * mux, GstBuffer * buf)
84 guint size = GST_BUFFER_SIZE (buf);
87 gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
88 ret = gst_pad_push (mux->srcpad, buf);
95 gst_mxf_mux_base_init (gpointer g_class)
97 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
98 const GstPadTemplate **p;
100 gst_element_class_add_static_pad_template (element_class, &src_templ);
102 p = mxf_essence_element_writer_get_pad_templates ();
104 gst_element_class_add_pad_template (element_class,
105 (GstPadTemplate *) (GST_OBJECT (*p)));
109 gst_element_class_set_details_simple (element_class, "MXF muxer",
111 "Muxes video/audio streams into a MXF stream",
112 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
116 gst_mxf_mux_class_init (GstMXFMuxClass * klass)
118 GObjectClass *gobject_class;
119 GstElementClass *gstelement_class;
121 GST_DEBUG_CATEGORY_INIT (mxfmux_debug, "mxfmux", 0, "MXF muxer");
123 gobject_class = (GObjectClass *) klass;
124 gstelement_class = (GstElementClass *) klass;
126 gobject_class->finalize = gst_mxf_mux_finalize;
127 gobject_class->set_property = gst_mxf_mux_set_property;
128 gobject_class->get_property = gst_mxf_mux_get_property;
130 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_mxf_mux_change_state);
131 gstelement_class->request_new_pad =
132 GST_DEBUG_FUNCPTR (gst_mxf_mux_request_new_pad);
133 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_mxf_mux_release_pad);
137 gst_mxf_mux_init (GstMXFMux * mux, GstMXFMuxClass * g_class)
141 mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
142 gst_pad_set_event_function (mux->srcpad, gst_mxf_mux_handle_src_event);
143 caps = gst_caps_new_simple ("application/mxf", NULL);
144 gst_pad_set_caps (mux->srcpad, caps);
145 gst_caps_unref (caps);
146 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
148 mux->collect = gst_collect_pads_new ();
149 gst_collect_pads_set_function (mux->collect,
150 (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_mxf_mux_collected), mux);
152 gst_mxf_mux_reset (mux);
156 gst_mxf_mux_finalize (GObject * object)
158 GstMXFMux *mux = GST_MXF_MUX (object);
160 gst_mxf_mux_reset (mux);
163 g_hash_table_destroy (mux->metadata);
164 mux->metadata = NULL;
165 g_list_free (mux->metadata_list);
166 mux->metadata_list = NULL;
169 gst_object_unref (mux->collect);
171 G_OBJECT_CLASS (parent_class)->finalize (object);
175 gst_mxf_mux_set_property (GObject * object,
176 guint prop_id, const GValue * value, GParamSpec * pspec)
178 //GstMXFMux *mux = GST_MXF_MUX (object);
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188 gst_mxf_mux_get_property (GObject * object,
189 guint prop_id, GValue * value, GParamSpec * pspec)
191 //GstMXFMux *mux = GST_MXF_MUX (object);
195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201 gst_mxf_mux_reset (GstMXFMux * mux)
205 while ((sl = mux->collect->data) != NULL) {
206 GstMXFMuxPad *cpad = (GstMXFMuxPad *) sl->data;
208 g_object_unref (cpad->adapter);
209 g_free (cpad->mapping_data);
211 gst_collect_pads_remove_pad (mux->collect, cpad->collect.pad);
214 mux->state = GST_MXF_MUX_STATE_HEADER;
218 g_hash_table_destroy (mux->metadata);
220 g_list_free (mux->metadata_list);
221 mux->metadata_list = NULL;
223 mux->metadata = mxf_metadata_hash_table_new ();
225 mxf_partition_pack_reset (&mux->partition);
226 mxf_primer_pack_reset (&mux->primer);
227 memset (&mux->min_edit_rate, 0, sizeof (MXFFraction));
228 mux->last_gc_timestamp = 0;
229 mux->last_gc_position = 0;
234 gst_mxf_mux_handle_src_event (GstPad * pad, GstEvent * event)
238 type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
242 /* disable seeking for now */
248 return gst_pad_event_default (pad, event);
252 gst_mxf_mux_handle_sink_event (GstPad * pad, GstEvent * event)
254 GstMXFMux *mux = GST_MXF_MUX (gst_pad_get_parent (pad));
257 switch (GST_EVENT_TYPE (event)) {
259 /* TODO: do something with the tags */
261 case GST_EVENT_NEWSEGMENT:
262 /* We don't support NEWSEGMENT events */
264 gst_event_unref (event);
270 /* now GstCollectPads can take care of the rest, e.g. EOS */
272 ret = mux->collect_event (pad, event);
273 gst_object_unref (mux);
279 gst_mxf_mux_setcaps (GstPad * pad, GstCaps * caps)
281 GstMXFMux *mux = GST_MXF_MUX (gst_pad_get_parent (pad));
282 GstMXFMuxPad *cpad = (GstMXFMuxPad *) gst_pad_get_element_private (pad);
284 MXFUUID d_instance_uid = { {0,} };
285 MXFMetadataFileDescriptor *old_descriptor = cpad->descriptor;
288 GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps);
290 if (old_descriptor) {
291 memcpy (&d_instance_uid, &MXF_METADATA_BASE (old_descriptor)->instance_uid,
293 cpad->descriptor = NULL;
294 g_free (cpad->mapping_data);
295 cpad->mapping_data = NULL;
299 cpad->writer->get_descriptor (gst_pad_get_pad_template (pad), caps,
300 &cpad->write_func, &cpad->mapping_data);
302 if (!cpad->descriptor) {
303 GST_ERROR_OBJECT (mux,
304 "Couldn't get descriptor for pad '%s' with caps %" GST_PTR_FORMAT,
305 GST_PAD_NAME (pad), caps);
306 gst_object_unref (mux);
310 if (mxf_uuid_is_zero (&d_instance_uid))
311 mxf_uuid_init (&d_instance_uid, mux->metadata);
313 memcpy (&MXF_METADATA_BASE (cpad->descriptor)->instance_uid, &d_instance_uid,
316 if (old_descriptor) {
317 for (l = mux->metadata_list; l; l = l->next) {
318 MXFMetadataBase *tmp = l->data;
320 if (mxf_uuid_is_equal (&d_instance_uid, &tmp->instance_uid)) {
321 l->data = cpad->descriptor;
326 mux->metadata_list = g_list_prepend (mux->metadata_list, cpad->descriptor);
329 g_hash_table_replace (mux->metadata,
330 &MXF_METADATA_BASE (cpad->descriptor)->instance_uid, cpad->descriptor);
332 if (old_descriptor) {
333 if (mux->preface && mux->preface->content_storage &&
334 mux->preface->content_storage->packages) {
337 for (i = 0; i < mux->preface->content_storage->n_packages; i++) {
338 MXFMetadataSourcePackage *package;
340 if (!MXF_IS_METADATA_SOURCE_PACKAGE (mux->preface->content_storage->
345 MXF_METADATA_SOURCE_PACKAGE (mux->preface->content_storage->
348 if (!package->descriptor)
351 if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor)) {
352 MXFMetadataMultipleDescriptor *tmp =
353 MXF_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor);
355 for (j = 0; j < tmp->n_sub_descriptors; j++) {
356 if (tmp->sub_descriptors[j] ==
357 MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
358 tmp->sub_descriptors[j] =
359 MXF_METADATA_GENERIC_DESCRIPTOR (cpad->descriptor);
360 memcpy (&tmp->sub_descriptors_uids[j], &d_instance_uid, 16);
363 } else if (package->descriptor ==
364 MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
365 package->descriptor =
366 MXF_METADATA_GENERIC_DESCRIPTOR (cpad->descriptor);
367 memcpy (&package->descriptor_uid, &d_instance_uid, 16);
373 gst_object_unref (mux);
379 gst_mxf_mux_create_pad_name (GstPadTemplate * templ, guint id)
383 string = g_string_new (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
384 g_string_truncate (string, string->len - 2);
385 g_string_append_printf (string, "%u", id);
387 return g_string_free (string, FALSE);
391 gst_mxf_mux_request_new_pad (GstElement * element,
392 GstPadTemplate * templ, const gchar * pad_name)
394 GstMXFMux *mux = GST_MXF_MUX (element);
399 const MXFEssenceElementWriter *writer;
401 if (mux->state != GST_MXF_MUX_STATE_HEADER) {
402 GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
406 writer = mxf_essence_element_writer_find (templ);
408 GST_ERROR_OBJECT (mux, "Not our template");
411 #if GLIB_CHECK_VERSION(2,29,5)
412 pad_number = g_atomic_int_add ((gint *) & mux->n_pads, 1);
414 pad_number = g_atomic_int_exchange_and_add ((gint *) & mux->n_pads, 1);
416 name = gst_mxf_mux_create_pad_name (templ, pad_number);
418 GST_DEBUG_OBJECT (mux, "Creating pad '%s'", name);
419 pad = gst_pad_new_from_template (templ, name);
421 cpad = (GstMXFMuxPad *)
422 gst_collect_pads_add_pad (mux->collect, pad, sizeof (GstMXFMuxPad));
423 cpad->last_timestamp = 0;
424 cpad->adapter = gst_adapter_new ();
425 cpad->writer = writer;
427 /* FIXME: hacked way to override/extend the event function of
428 * GstCollectPads; because it sets its own event function giving the
429 * element no access to events.
431 mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (pad);
432 gst_pad_set_event_function (pad,
433 GST_DEBUG_FUNCPTR (gst_mxf_mux_handle_sink_event));
435 gst_pad_set_setcaps_function (pad, gst_mxf_mux_setcaps);
436 gst_pad_use_fixed_caps (pad);
437 gst_pad_set_active (pad, TRUE);
438 gst_element_add_pad (element, pad);
444 gst_mxf_mux_release_pad (GstElement * element, GstPad * pad)
446 /*GstMXFMux *mux = GST_MXF_MUX (GST_PAD_PARENT (pad));
447 GstMXFMuxPad *cpad = (GstMXFMuxPad *) gst_pad_get_element_private (pad);
449 g_object_unref (cpad->adapter);
450 g_free (cpad->mapping_data);
452 gst_collect_pads_remove_pad (mux->collect, pad);
453 gst_element_remove_pad (element, pad); */
457 gst_mxf_mux_create_metadata (GstMXFMux * mux)
459 GstFlowReturn ret = GST_FLOW_OK;
463 GST_DEBUG_OBJECT (mux, "Creating MXF metadata");
465 for (l = mux->collect->data; l; l = l->next) {
466 GstMXFMuxPad *cpad = l->data;
468 if (!cpad || !cpad->descriptor || !GST_PAD_CAPS (cpad->collect.pad))
469 return GST_FLOW_ERROR;
471 if (cpad->writer->update_descriptor)
472 cpad->writer->update_descriptor (cpad->descriptor,
473 GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
474 cpad->collect.buffer);
479 (MXFMetadataPreface *) gst_mini_object_new (MXF_TYPE_METADATA_PREFACE);
480 mxf_uuid_init (&MXF_METADATA_BASE (mux->preface)->instance_uid,
482 g_hash_table_insert (mux->metadata,
483 &MXF_METADATA_BASE (mux->preface)->instance_uid, mux->preface);
484 mux->metadata_list = g_list_prepend (mux->metadata_list, mux->preface);
486 mxf_timestamp_set_now (&mux->preface->last_modified_date);
487 mux->preface->version = 258;
488 mux->preface->object_model_version = 1;
490 mxf_op_set_generalized (&mux->preface->operational_pattern, MXF_OP_1a, TRUE,
493 tmp = g_array_new (FALSE, FALSE, sizeof (MXFUL));
494 for (l = mux->collect->data; l; l = l->next) {
495 GstMXFMuxPad *cpad = l->data;
497 gboolean found = FALSE;
499 if (!cpad || !cpad->descriptor ||
500 mxf_ul_is_zero (&cpad->descriptor->essence_container))
501 return GST_FLOW_ERROR;
503 for (i = 0; i < tmp->len; i++) {
504 if (mxf_ul_is_equal (&cpad->descriptor->essence_container,
505 &g_array_index (tmp, MXFUL, i))) {
514 g_array_append_val (tmp, cpad->descriptor->essence_container);
516 mux->preface->n_essence_containers = tmp->len;
517 mux->preface->essence_containers = (MXFUL *) g_array_free (tmp, FALSE);
519 /* This will later be used as UID for the material package */
520 mxf_uuid_init (&mux->preface->primary_package_uid, mux->metadata);
522 /* Identifications */
524 MXFMetadataIdentification *identification;
525 static const guint8 gst_uid[] = {
526 0xe5, 0xde, 0xcd, 0x04, 0x24, 0x90, 0x69, 0x18,
527 0x8a, 0xc9, 0xb5, 0xd7, 0x02, 0x58, 0x46, 0x78
529 guint major, minor, micro, nano;
531 mux->preface->n_identifications = 1;
532 mux->preface->identifications = g_new0 (MXFMetadataIdentification *, 1);
533 identification = mux->preface->identifications[0] =
534 (MXFMetadataIdentification *)
535 gst_mini_object_new (MXF_TYPE_METADATA_IDENTIFICATION);
537 mxf_uuid_init (&MXF_METADATA_BASE (identification)->instance_uid,
539 g_hash_table_insert (mux->metadata,
540 &MXF_METADATA_BASE (identification)->instance_uid, identification);
541 mux->metadata_list = g_list_prepend (mux->metadata_list, identification);
543 mxf_uuid_init (&identification->this_generation_uid, NULL);
545 identification->company_name = g_strdup ("GStreamer");
546 identification->product_name = g_strdup ("GStreamer Multimedia Framework");
548 gst_version (&major, &minor, µ, &nano);
549 identification->product_version.major = major;
550 identification->product_version.minor = minor;
551 identification->product_version.patch = micro;
552 identification->product_version.build = nano;
553 identification->product_version.release =
554 (nano == 0) ? 1 : (nano == 1) ? 2 : 4;
556 identification->version_string =
557 g_strdup_printf ("%u.%u.%u.%u", major, minor, micro, nano);
558 memcpy (&identification->product_uid, &gst_uid, 16);
560 memcpy (&identification->modification_date,
561 &mux->preface->last_modified_date, sizeof (MXFTimestamp));
562 memcpy (&identification->toolkit_version, &identification->product_version,
563 sizeof (MXFProductVersion));
565 #ifdef HAVE_SYS_UTSNAME_H
567 struct utsname sys_details;
569 if (uname (&sys_details) == 0) {
570 identification->platform = g_strdup_printf ("%s %s %s",
571 sys_details.sysname, sys_details.release, sys_details.machine);
576 #if defined(G_OS_WIN32)
577 if (identification->platform == NULL)
578 identification->platform = g_strdup ("Microsoft Windows");
579 #elif defined(G_OS_BEOS)
580 if (identification->platform == NULL)
581 identification->platform = g_strdup ("BEOS");
582 #elif defined(G_OS_UNIX)
583 if (identification->platform == NULL)
584 identification->platform = g_strdup ("Unix");
588 /* Content storage */
590 MXFMetadataContentStorage *cstorage;
593 cstorage = mux->preface->content_storage = (MXFMetadataContentStorage *)
594 gst_mini_object_new (MXF_TYPE_METADATA_CONTENT_STORAGE);
595 mxf_uuid_init (&MXF_METADATA_BASE (cstorage)->instance_uid, mux->metadata);
596 g_hash_table_insert (mux->metadata,
597 &MXF_METADATA_BASE (cstorage)->instance_uid, cstorage);
598 mux->metadata_list = g_list_prepend (mux->metadata_list, cstorage);
600 cstorage->n_packages = 2;
601 cstorage->packages = g_new0 (MXFMetadataGenericPackage *, 2);
605 MXFMetadataSourcePackage *p;
607 cstorage->packages[1] = (MXFMetadataGenericPackage *)
608 gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_PACKAGE);
609 mxf_uuid_init (&MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
611 g_hash_table_insert (mux->metadata,
612 &MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
613 cstorage->packages[1]);
615 g_list_prepend (mux->metadata_list, cstorage->packages[1]);
616 p = (MXFMetadataSourcePackage *) cstorage->packages[1];
618 mxf_umid_init (&p->parent.package_uid);
619 p->parent.name = g_strdup ("Source package");
620 memcpy (&p->parent.package_creation_date,
621 &mux->preface->last_modified_date, sizeof (MXFTimestamp));
622 memcpy (&p->parent.package_modified_date,
623 &mux->preface->last_modified_date, sizeof (MXFTimestamp));
625 p->parent.n_tracks = g_slist_length (mux->collect->data);
626 p->parent.tracks = g_new0 (MXFMetadataTrack *, p->parent.n_tracks);
628 if (p->parent.n_tracks > 1) {
629 MXFMetadataMultipleDescriptor *d;
631 p->descriptor = (MXFMetadataGenericDescriptor *)
632 gst_mini_object_new (MXF_TYPE_METADATA_MULTIPLE_DESCRIPTOR);
633 d = (MXFMetadataMultipleDescriptor *) p->descriptor;
634 d->n_sub_descriptors = p->parent.n_tracks;
636 g_new0 (MXFMetadataGenericDescriptor *, p->parent.n_tracks);
638 mxf_uuid_init (&MXF_METADATA_BASE (d)->instance_uid, mux->metadata);
639 g_hash_table_insert (mux->metadata,
640 &MXF_METADATA_BASE (d)->instance_uid, d);
641 mux->metadata_list = g_list_prepend (mux->metadata_list, d);
649 for (l = mux->collect->data; l; l = l->next) {
650 GstMXFMuxPad *cpad = l->data;
651 MXFMetadataTimelineTrack *track;
652 MXFMetadataSequence *sequence;
653 MXFMetadataSourceClip *clip;
655 p->parent.tracks[n] = (MXFMetadataTrack *)
656 gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
657 track = (MXFMetadataTimelineTrack *) p->parent.tracks[n];
658 mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
660 g_hash_table_insert (mux->metadata,
661 &MXF_METADATA_BASE (track)->instance_uid, track);
662 mux->metadata_list = g_list_prepend (mux->metadata_list, track);
664 track->parent.track_id = n + 1;
665 track->parent.track_number =
666 cpad->writer->get_track_number_template (cpad->descriptor,
667 GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data);
669 cpad->writer->get_edit_rate (cpad->descriptor,
670 GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
671 cpad->collect.buffer, p, track, &track->edit_rate);
673 sequence = track->parent.sequence = (MXFMetadataSequence *)
674 gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
675 mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
677 g_hash_table_insert (mux->metadata,
678 &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
679 mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
681 memcpy (&sequence->data_definition, &cpad->writer->data_definition,
684 sequence->n_structural_components = 1;
685 sequence->structural_components =
686 g_new0 (MXFMetadataStructuralComponent *, 1);
688 clip = (MXFMetadataSourceClip *)
689 gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_CLIP);
690 sequence->structural_components[0] =
691 (MXFMetadataStructuralComponent *) clip;
692 mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
694 g_hash_table_insert (mux->metadata,
695 &MXF_METADATA_BASE (clip)->instance_uid, clip);
696 mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
698 memcpy (&clip->parent.data_definition, &sequence->data_definition,
700 clip->start_position = 0;
702 cpad->source_package = p;
703 cpad->source_track = track;
704 cpad->descriptor->linked_track_id = n + 1;
705 if (p->parent.n_tracks == 1) {
706 p->descriptor = (MXFMetadataGenericDescriptor *) cpad->descriptor;
708 MXF_METADATA_MULTIPLE_DESCRIPTOR (p->descriptor)->
710 (MXFMetadataGenericDescriptor *) cpad->descriptor;
718 /* Material package */
720 MXFMetadataMaterialPackage *p;
721 MXFFraction min_edit_rate = { 0, 0 };
722 gdouble min_edit_rate_d = G_MAXDOUBLE;
724 cstorage->packages[0] = (MXFMetadataGenericPackage *)
725 gst_mini_object_new (MXF_TYPE_METADATA_MATERIAL_PACKAGE);
726 memcpy (&MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
727 &mux->preface->primary_package_uid, 16);
728 g_hash_table_insert (mux->metadata,
729 &MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
730 cstorage->packages[0]);
732 g_list_prepend (mux->metadata_list, cstorage->packages[0]);
733 p = (MXFMetadataMaterialPackage *) cstorage->packages[0];
735 mxf_umid_init (&p->package_uid);
736 p->name = g_strdup ("Material package");
737 memcpy (&p->package_creation_date, &mux->preface->last_modified_date,
738 sizeof (MXFTimestamp));
739 memcpy (&p->package_modified_date, &mux->preface->last_modified_date,
740 sizeof (MXFTimestamp));
742 p->n_tracks = g_slist_length (mux->collect->data) + 1;
743 p->tracks = g_new0 (MXFMetadataTrack *, p->n_tracks);
751 for (l = mux->collect->data; l; l = l->next) {
752 GstMXFMuxPad *cpad = l->data;
753 MXFMetadataSourcePackage *source_package;
754 MXFMetadataTimelineTrack *track, *source_track;
755 MXFMetadataSequence *sequence;
756 MXFMetadataSourceClip *clip;
758 source_package = MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
760 MXF_METADATA_TIMELINE_TRACK (source_package->parent.tracks[n -
763 p->tracks[n] = (MXFMetadataTrack *)
764 gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
765 track = (MXFMetadataTimelineTrack *) p->tracks[n];
766 mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
768 g_hash_table_insert (mux->metadata,
769 &MXF_METADATA_BASE (track)->instance_uid, track);
770 mux->metadata_list = g_list_prepend (mux->metadata_list, track);
772 track->parent.track_id = n + 1;
773 track->parent.track_number = 0;
775 cpad->writer->get_edit_rate (cpad->descriptor,
776 GST_PAD_CAPS (cpad->collect.pad), cpad->mapping_data,
777 cpad->collect.buffer, source_package, source_track,
780 if (track->edit_rate.n != source_track->edit_rate.n ||
781 track->edit_rate.d != source_track->edit_rate.d) {
782 memcpy (&source_track->edit_rate, &track->edit_rate,
783 sizeof (MXFFraction));
786 if (track->edit_rate.d <= 0 || track->edit_rate.n <= 0) {
787 GST_ERROR_OBJECT (mux, "Invalid edit rate");
788 return GST_FLOW_ERROR;
791 if (min_edit_rate_d >
792 ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d)) {
794 ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d);
795 memcpy (&min_edit_rate, &track->edit_rate, sizeof (MXFFraction));
798 sequence = track->parent.sequence = (MXFMetadataSequence *)
799 gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
800 mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
802 g_hash_table_insert (mux->metadata,
803 &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
804 mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
806 memcpy (&sequence->data_definition, &cpad->writer->data_definition,
808 sequence->n_structural_components = 1;
809 sequence->structural_components =
810 g_new0 (MXFMetadataStructuralComponent *, 1);
812 clip = (MXFMetadataSourceClip *)
813 gst_mini_object_new (MXF_TYPE_METADATA_SOURCE_CLIP);
814 sequence->structural_components[0] =
815 (MXFMetadataStructuralComponent *) clip;
816 mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
818 g_hash_table_insert (mux->metadata,
819 &MXF_METADATA_BASE (clip)->instance_uid, clip);
820 mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
822 memcpy (&clip->parent.data_definition, &sequence->data_definition,
824 clip->start_position = 0;
826 memcpy (&clip->source_package_id, &cstorage->packages[1]->package_uid,
828 clip->source_track_id = n;
836 MXFMetadataTimelineTrack *track;
837 MXFMetadataSequence *sequence;
838 MXFMetadataTimecodeComponent *component;
840 p->tracks[n] = (MXFMetadataTrack *)
841 gst_mini_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK);
842 track = (MXFMetadataTimelineTrack *) p->tracks[n];
843 mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
845 g_hash_table_insert (mux->metadata,
846 &MXF_METADATA_BASE (track)->instance_uid, track);
847 mux->metadata_list = g_list_prepend (mux->metadata_list, track);
849 track->parent.track_id = n + 1;
850 track->parent.track_number = 0;
851 track->parent.track_name = g_strdup ("Timecode track");
852 /* FIXME: Is this correct? */
853 memcpy (&track->edit_rate, &min_edit_rate, sizeof (MXFFraction));
855 sequence = track->parent.sequence = (MXFMetadataSequence *)
856 gst_mini_object_new (MXF_TYPE_METADATA_SEQUENCE);
857 mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
859 g_hash_table_insert (mux->metadata,
860 &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
861 mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
863 memcpy (&sequence->data_definition,
864 mxf_metadata_track_identifier_get
865 (MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE), 16);
867 sequence->n_structural_components = 1;
868 sequence->structural_components =
869 g_new0 (MXFMetadataStructuralComponent *, 1);
871 component = (MXFMetadataTimecodeComponent *)
872 gst_mini_object_new (MXF_TYPE_METADATA_TIMECODE_COMPONENT);
873 sequence->structural_components[0] =
874 (MXFMetadataStructuralComponent *) component;
875 mxf_uuid_init (&MXF_METADATA_BASE (component)->instance_uid,
877 g_hash_table_insert (mux->metadata,
878 &MXF_METADATA_BASE (component)->instance_uid, component);
879 mux->metadata_list = g_list_prepend (mux->metadata_list, component);
881 memcpy (&component->parent.data_definition,
882 &sequence->data_definition, 16);
884 component->start_timecode = 0;
885 component->rounded_timecode_base =
886 (((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d) +
888 /* TODO: drop frame */
891 memcpy (&mux->min_edit_rate, &min_edit_rate, sizeof (MXFFraction));
895 for (i = 0; i < cstorage->packages[1]->n_tracks; i++) {
896 MXFMetadataTrack *track = cstorage->packages[1]->tracks[i];
901 if ((track->track_number & 0x00ff00ff) != 0)
904 templ = track->track_number;
907 for (j = 0; j < cstorage->packages[1]->n_tracks; j++) {
908 MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
910 if (tmp->track_number == templ) {
916 for (j = 0; j < cstorage->packages[1]->n_tracks; j++) {
917 MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
919 if (tmp->track_number == templ) {
921 tmp->track_number |= (n_type << 16) | (n);
926 cstorage->n_essence_container_data = 1;
927 cstorage->essence_container_data =
928 g_new0 (MXFMetadataEssenceContainerData *, 1);
929 cstorage->essence_container_data[0] = (MXFMetadataEssenceContainerData *)
930 gst_mini_object_new (MXF_TYPE_METADATA_ESSENCE_CONTAINER_DATA);
931 mxf_uuid_init (&MXF_METADATA_BASE (cstorage->essence_container_data[0])->
932 instance_uid, mux->metadata);
933 g_hash_table_insert (mux->metadata,
934 &MXF_METADATA_BASE (cstorage->essence_container_data[0])->instance_uid,
935 cstorage->essence_container_data[0]);
937 g_list_prepend (mux->metadata_list,
938 cstorage->essence_container_data[0]);
940 cstorage->essence_container_data[0]->linked_package =
941 MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
942 cstorage->essence_container_data[0]->index_sid = 0;
943 cstorage->essence_container_data[0]->body_sid = 1;
946 /* Sort descriptors at the correct places */
949 GList *descriptors = NULL;
951 for (l = mux->metadata_list; l; l = l->next) {
952 MXFMetadataBase *m = l->data;
954 if (MXF_IS_METADATA_GENERIC_DESCRIPTOR (m)
955 && !MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m)) {
957 l->prev->next = NULL;
963 g_assert (descriptors != NULL);
965 for (l = mux->metadata_list; l; l = l->next) {
966 MXFMetadataBase *m = l->data;
969 if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m) ||
970 MXF_IS_METADATA_SOURCE_PACKAGE (m)) {
972 l->prev = g_list_last (descriptors);
973 s->next = descriptors;
974 descriptors->prev = s;
981 mux->metadata_list = g_list_reverse (mux->metadata_list);
987 gst_mxf_mux_init_partition_pack (GstMXFMux * mux)
992 mxf_partition_pack_reset (&mux->partition);
993 mux->partition.type = MXF_PARTITION_PACK_HEADER;
994 mux->partition.closed = mux->partition.complete = FALSE;
995 mux->partition.major_version = 0x0001;
996 mux->partition.minor_version = 0x0002;
997 mux->partition.kag_size = 0;
998 mux->partition.this_partition = 0;
999 mux->partition.prev_partition = 0;
1000 mux->partition.footer_partition = 0;
1001 mux->partition.header_byte_count = 0;
1002 mux->partition.index_byte_count = 0;
1003 mux->partition.index_sid = 0;
1004 mux->partition.body_offset = 0;
1005 mux->partition.body_sid = 0;
1007 memcpy (&mux->partition.operational_pattern,
1008 &mux->preface->operational_pattern, 16);
1010 mux->partition.n_essence_containers = g_slist_length (mux->collect->data);
1011 mux->partition.essence_containers =
1012 g_new0 (MXFUL, mux->partition.n_essence_containers);
1014 for (l = mux->collect->data; l; l = l->next) {
1015 GstMXFMuxPad *cpad = l->data;
1017 gboolean found = FALSE;
1019 for (j = 0; j <= i; j++) {
1020 if (mxf_ul_is_equal (&cpad->descriptor->essence_container,
1021 &mux->partition.essence_containers[j])) {
1030 memcpy (&mux->partition.essence_containers[i],
1031 &cpad->descriptor->essence_container, 16);
1034 mux->partition.n_essence_containers = i;
1039 static GstFlowReturn
1040 gst_mxf_mux_write_header_metadata (GstMXFMux * mux)
1042 GstFlowReturn ret = GST_FLOW_OK;
1044 GList *buffers = NULL;
1047 guint64 header_byte_count = 0;
1049 for (l = mux->metadata_list; l; l = l->next) {
1051 buf = mxf_metadata_base_to_buffer (m, &mux->primer);
1052 header_byte_count += GST_BUFFER_SIZE (buf);
1053 buffers = g_list_prepend (buffers, buf);
1056 buffers = g_list_reverse (buffers);
1057 buf = mxf_primer_pack_to_buffer (&mux->primer);
1058 header_byte_count += GST_BUFFER_SIZE (buf);
1059 buffers = g_list_prepend (buffers, buf);
1061 mux->partition.header_byte_count = header_byte_count;
1062 buf = mxf_partition_pack_to_buffer (&mux->partition);
1063 if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1064 GST_ERROR_OBJECT (mux, "Failed pushing partition: %s",
1065 gst_flow_get_name (ret));
1066 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
1067 g_list_free (buffers);
1071 for (l = buffers; l; l = l->next) {
1074 if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1075 GST_ERROR_OBJECT (mux, "Failed pushing buffer: %s",
1076 gst_flow_get_name (ret));
1077 g_list_foreach (l, (GFunc) gst_mini_object_unref, NULL);
1078 g_list_free (buffers);
1083 g_list_free (buffers);
1088 static const guint8 _gc_essence_element_ul[] = {
1089 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x00,
1090 0x0d, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00
1093 static GstFlowReturn
1094 gst_mxf_mux_handle_buffer (GstMXFMux * mux, GstMXFMuxPad * cpad)
1096 GstBuffer *buf = NULL;
1097 GstBuffer *outbuf = NULL;
1099 GstFlowReturn ret = GST_FLOW_OK;
1100 guint8 slen, ber[9];
1102 (cpad->collect.abidata.ABI.eos && !cpad->have_complete_edit_unit
1103 && cpad->collect.buffer == NULL);
1105 if (cpad->have_complete_edit_unit) {
1106 GST_DEBUG_OBJECT (cpad->collect.pad,
1107 "Handling remaining buffer for track %u at position %" G_GINT64_FORMAT,
1108 cpad->source_track->parent.track_id, cpad->pos);
1110 } else if (!flush) {
1111 buf = gst_collect_pads_pop (mux->collect, &cpad->collect);
1115 GST_DEBUG_OBJECT (cpad->collect.pad,
1116 "Handling buffer of size %u for track %u at position %" G_GINT64_FORMAT,
1117 GST_BUFFER_SIZE (buf), cpad->source_track->parent.track_id, cpad->pos);
1120 GST_DEBUG_OBJECT (cpad->collect.pad,
1121 "Flushing for track %u at position %" G_GINT64_FORMAT,
1122 cpad->source_track->parent.track_id, cpad->pos);
1125 ret = cpad->write_func (buf, GST_PAD_CAPS (cpad->collect.pad),
1126 cpad->mapping_data, cpad->adapter, &outbuf, flush);
1127 if (ret != GST_FLOW_OK && ret != GST_FLOW_CUSTOM_SUCCESS) {
1128 GST_ERROR_OBJECT (cpad->collect.pad,
1129 "Failed handling buffer for track %u, reason %s",
1130 cpad->source_track->parent.track_id, gst_flow_get_name (ret));
1134 if (ret == GST_FLOW_CUSTOM_SUCCESS) {
1135 cpad->have_complete_edit_unit = TRUE;
1138 cpad->have_complete_edit_unit = FALSE;
1145 slen = mxf_ber_encode_size (GST_BUFFER_SIZE (buf), ber);
1146 packet = gst_buffer_new_and_alloc (16 + slen + GST_BUFFER_SIZE (buf));
1147 memcpy (GST_BUFFER_DATA (packet), _gc_essence_element_ul, 16);
1148 GST_BUFFER_DATA (packet)[7] = cpad->descriptor->essence_container.u[7];
1149 GST_WRITE_UINT32_BE (&GST_BUFFER_DATA (packet)[12],
1150 cpad->source_track->parent.track_number);
1151 memcpy (&GST_BUFFER_DATA (packet)[16], ber, slen);
1152 memcpy (&GST_BUFFER_DATA (packet)[16 + slen], GST_BUFFER_DATA (buf),
1153 GST_BUFFER_SIZE (buf));
1154 gst_buffer_unref (buf);
1156 GST_DEBUG_OBJECT (cpad->collect.pad, "Pushing buffer of size %u for track %u",
1157 GST_BUFFER_SIZE (packet), cpad->source_track->parent.track_id);
1159 if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
1160 GST_ERROR_OBJECT (cpad->collect.pad,
1161 "Failed pushing buffer for track %u, reason %s",
1162 cpad->source_track->parent.track_id, gst_flow_get_name (ret));
1167 cpad->last_timestamp =
1168 gst_util_uint64_scale (GST_SECOND * cpad->pos,
1169 cpad->source_track->edit_rate.d, cpad->source_track->edit_rate.n);
1174 static GstFlowReturn
1175 gst_mxf_mux_write_body_partition (GstMXFMux * mux)
1179 mux->partition.type = MXF_PARTITION_PACK_BODY;
1180 mux->partition.this_partition = mux->offset;
1181 mux->partition.prev_partition = 0;
1182 mux->partition.footer_partition = 0;
1183 mux->partition.header_byte_count = 0;
1184 mux->partition.index_byte_count = 0;
1185 mux->partition.index_sid = 0;
1186 mux->partition.body_offset = 0;
1187 mux->partition.body_sid =
1188 mux->preface->content_storage->essence_container_data[0]->body_sid;
1190 buf = mxf_partition_pack_to_buffer (&mux->partition);
1191 return gst_mxf_mux_push (mux, buf);
1194 static GstFlowReturn
1195 gst_mxf_mux_handle_eos (GstMXFMux * mux)
1198 gboolean have_data = FALSE;
1202 GstMXFMuxPad *best = NULL;
1206 for (l = mux->collect->data; l; l = l->next) {
1207 GstMXFMuxPad *cpad = l->data;
1208 GstClockTime next_gc_timestamp =
1209 gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1210 mux->min_edit_rate.d, mux->min_edit_rate.n);
1214 if (cpad->have_complete_edit_unit ||
1215 gst_adapter_available (cpad->adapter) > 0 || cpad->collect.buffer) {
1217 if (cpad->last_timestamp < next_gc_timestamp) {
1223 if (have_data && !l->next) {
1224 mux->last_gc_position++;
1225 mux->last_gc_timestamp = next_gc_timestamp;
1232 gst_mxf_mux_handle_buffer (mux, best);
1235 } while (have_data);
1237 mux->last_gc_position++;
1238 mux->last_gc_timestamp =
1239 gst_util_uint64_scale (mux->last_gc_position * GST_SECOND,
1240 mux->min_edit_rate.d, mux->min_edit_rate.n);
1242 /* Update essence track durations */
1243 for (l = mux->collect->data; l; l = l->next) {
1244 GstMXFMuxPad *cpad = l->data;
1247 /* Update durations */
1248 cpad->source_track->parent.sequence->duration = cpad->pos;
1249 MXF_METADATA_SOURCE_CLIP (cpad->source_track->parent.sequence->
1250 structural_components[0])->parent.duration = cpad->pos;
1251 for (i = 0; i < mux->preface->content_storage->packages[0]->n_tracks; i++) {
1252 MXFMetadataTimelineTrack *track;
1254 if (!MXF_IS_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
1255 packages[0]->tracks[i])
1256 || !MXF_IS_METADATA_SOURCE_CLIP (mux->preface->content_storage->
1257 packages[0]->tracks[i]->sequence->structural_components[0]))
1261 MXF_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
1262 packages[0]->tracks[i]);
1263 if (MXF_METADATA_SOURCE_CLIP (track->parent.sequence->
1264 structural_components[0])->source_track_id ==
1265 cpad->source_track->parent.track_id) {
1266 track->parent.sequence->structural_components[0]->duration = cpad->pos;
1267 track->parent.sequence->duration = cpad->pos;
1272 /* Update timecode track duration */
1274 MXFMetadataTimelineTrack *track =
1275 MXF_METADATA_TIMELINE_TRACK (mux->preface->content_storage->
1276 packages[0]->tracks[0]);
1277 MXFMetadataSequence *sequence = track->parent.sequence;
1278 MXFMetadataTimecodeComponent *component =
1279 MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1281 sequence->duration = mux->last_gc_position;
1282 component->parent.duration = mux->last_gc_position;
1286 guint64 body_partition = mux->partition.this_partition;
1287 guint32 body_sid = mux->partition.body_sid;
1288 guint64 footer_partition = mux->offset;
1291 MXFRandomIndexPackEntry entry;
1293 mux->partition.type = MXF_PARTITION_PACK_FOOTER;
1294 mux->partition.closed = TRUE;
1295 mux->partition.complete = TRUE;
1296 mux->partition.this_partition = mux->offset;
1297 mux->partition.prev_partition = body_partition;
1298 mux->partition.footer_partition = mux->offset;
1299 mux->partition.header_byte_count = 0;
1300 mux->partition.index_byte_count = 0;
1301 mux->partition.index_sid = 0;
1302 mux->partition.body_offset = 0;
1303 mux->partition.body_sid = 0;
1305 gst_mxf_mux_write_header_metadata (mux);
1307 rip = g_array_sized_new (FALSE, FALSE, sizeof (MXFRandomIndexPackEntry), 3);
1310 g_array_append_val (rip, entry);
1311 entry.offset = body_partition;
1312 entry.body_sid = body_sid;
1313 g_array_append_val (rip, entry);
1314 entry.offset = footer_partition;
1316 g_array_append_val (rip, entry);
1318 packet = mxf_random_index_pack_to_buffer (rip);
1319 if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
1320 GST_ERROR_OBJECT (mux, "Failed pushing random index pack");
1322 g_array_free (rip, TRUE);
1324 /* Rewrite header partition with updated values */
1325 if (gst_pad_push_event (mux->srcpad,
1326 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1,
1329 mux->partition.type = MXF_PARTITION_PACK_HEADER;
1330 mux->partition.closed = TRUE;
1331 mux->partition.complete = TRUE;
1332 mux->partition.this_partition = 0;
1333 mux->partition.prev_partition = footer_partition;
1334 mux->partition.footer_partition = footer_partition;
1335 mux->partition.header_byte_count = 0;
1336 mux->partition.index_byte_count = 0;
1337 mux->partition.index_sid = 0;
1338 mux->partition.body_offset = 0;
1339 mux->partition.body_sid = 0;
1341 ret = gst_mxf_mux_write_header_metadata (mux);
1342 if (ret != GST_FLOW_OK) {
1343 GST_ERROR_OBJECT (mux, "Rewriting header partition failed");
1347 GST_WARNING_OBJECT (mux, "Can't rewrite header partition");
1355 _sort_mux_pads (gconstpointer a, gconstpointer b)
1357 const GstMXFMuxPad *pa = a, *pb = b;
1358 MXFMetadataTrackType ta =
1359 mxf_metadata_track_identifier_parse (&pa->writer->data_definition);
1360 MXFMetadataTrackType tb =
1361 mxf_metadata_track_identifier_parse (&pb->writer->data_definition);
1366 return pa->source_track->parent.track_number -
1367 pa->source_track->parent.track_number;
1370 static GstFlowReturn
1371 gst_mxf_mux_collected (GstCollectPads * pads, gpointer user_data)
1373 GstMXFMux *mux = GST_MXF_MUX (user_data);
1374 GstMXFMuxPad *best = NULL;
1377 gboolean eos = TRUE;
1379 if (mux->state == GST_MXF_MUX_STATE_ERROR) {
1380 GST_ERROR_OBJECT (mux, "Had an error before -- returning");
1381 return GST_FLOW_ERROR;
1382 } else if (mux->state == GST_MXF_MUX_STATE_EOS) {
1383 GST_WARNING_OBJECT (mux, "EOS");
1384 return GST_FLOW_UNEXPECTED;
1387 if (mux->state == GST_MXF_MUX_STATE_HEADER) {
1388 if (mux->collect->data == NULL) {
1389 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1390 ("No input streams configured"));
1391 ret = GST_FLOW_ERROR;
1395 if (gst_pad_push_event (mux->srcpad,
1396 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1,
1398 if ((ret = gst_mxf_mux_create_metadata (mux)) != GST_FLOW_OK)
1401 if ((ret = gst_mxf_mux_init_partition_pack (mux)) != GST_FLOW_OK)
1404 ret = gst_mxf_mux_write_header_metadata (mux);
1406 ret = GST_FLOW_ERROR;
1409 if (ret != GST_FLOW_OK)
1412 /* Sort pads, we will always write in that order */
1413 mux->collect->data = g_slist_sort (mux->collect->data, _sort_mux_pads);
1415 /* Write body partition */
1416 ret = gst_mxf_mux_write_body_partition (mux);
1417 if (ret != GST_FLOW_OK)
1419 mux->state = GST_MXF_MUX_STATE_DATA;
1422 g_return_val_if_fail (g_hash_table_size (mux->metadata) > 0, GST_FLOW_ERROR);
1425 for (sl = mux->collect->data; sl; sl = sl->next) {
1426 GstMXFMuxPad *cpad = sl->data;
1427 GstClockTime next_gc_timestamp =
1428 gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1429 mux->min_edit_rate.d, mux->min_edit_rate.n);
1431 eos &= cpad->collect.abidata.ABI.eos;
1433 if ((!cpad->collect.abidata.ABI.eos || cpad->have_complete_edit_unit ||
1434 gst_adapter_available (cpad->adapter) > 0 || cpad->collect.buffer)
1435 && cpad->last_timestamp < next_gc_timestamp) {
1438 } else if (!eos && !sl->next) {
1439 mux->last_gc_position++;
1440 mux->last_gc_timestamp = next_gc_timestamp;
1446 } while (!eos && best == NULL);
1449 ret = gst_mxf_mux_handle_buffer (mux, best);
1450 if (ret != GST_FLOW_OK)
1453 GST_DEBUG_OBJECT (mux, "Handling EOS");
1455 gst_mxf_mux_handle_eos (mux);
1456 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
1457 mux->state = GST_MXF_MUX_STATE_EOS;
1458 return GST_FLOW_UNEXPECTED;
1465 mux->state = GST_MXF_MUX_STATE_ERROR;
1466 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
1471 static GstStateChangeReturn
1472 gst_mxf_mux_change_state (GstElement * element, GstStateChange transition)
1474 GstStateChangeReturn ret;
1475 GstMXFMux *mux = GST_MXF_MUX (element);
1477 switch (transition) {
1478 case GST_STATE_CHANGE_NULL_TO_READY:
1480 case GST_STATE_CHANGE_READY_TO_PAUSED:
1481 gst_collect_pads_start (mux->collect);
1483 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1485 case GST_STATE_CHANGE_PAUSED_TO_READY:
1486 gst_collect_pads_stop (mux->collect);
1492 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1494 switch (transition) {
1495 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1497 case GST_STATE_CHANGE_PAUSED_TO_READY:
1498 gst_mxf_mux_reset (mux);
1500 case GST_STATE_CHANGE_READY_TO_NULL: