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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * SECTION:element-mxfmux
24 * mxfmux muxes different streams into an MXF file.
26 * ## Example launch line
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.
40 #include "gstmxfelements.h"
43 #ifdef HAVE_SYS_UTSNAME_H
44 #include <sys/utsname.h>
47 GST_DEBUG_CATEGORY_STATIC (mxfmux_debug);
48 #define GST_CAT_DEFAULT mxfmux_debug
50 #define GST_TYPE_MXF_MUX_PAD (gst_mxf_mux_pad_get_type())
51 #define GST_MXF_MUX_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MXF_MUX_PAD, GstMXFMuxPad))
52 #define GST_MXF_MUX_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MXF_MUX_PAD, GstMXFMuxPadClass))
53 #define GST_MXF_MUX_PAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_MXF_MUX_PAD, GstMXFMuxPadClass))
54 #define GST_IS_MXF_MUX_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MXF_MUX_PAD))
55 #define GST_IS_MXF_MUX_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MXF_MUX_PAD))
59 GstAggregatorPad parent;
62 GstClockTime last_timestamp;
64 MXFMetadataFileDescriptor *descriptor;
67 gboolean have_complete_edit_unit;
69 gpointer mapping_data;
70 const MXFEssenceElementWriter *writer;
71 MXFEssenceElementWriteFunc write_func;
73 MXFMetadataSourcePackage *source_package;
74 MXFMetadataTimelineTrack *source_track;
79 GstAggregatorPadClass parent_class;
82 GType gst_mxf_mux_pad_get_type (void);
84 G_DEFINE_TYPE (GstMXFMuxPad, gst_mxf_mux_pad, GST_TYPE_AGGREGATOR_PAD);
87 gst_mxf_mux_pad_finalize (GObject * object)
89 GstMXFMuxPad *pad = GST_MXF_MUX_PAD (object);
91 g_object_unref (pad->adapter);
92 g_free (pad->mapping_data);
94 G_OBJECT_CLASS (gst_mxf_mux_pad_parent_class)->finalize (object);
98 gst_mxf_mux_pad_class_init (GstMXFMuxPadClass * klass)
100 GObjectClass *object_class = (GObjectClass *) klass;
102 object_class->finalize = gst_mxf_mux_pad_finalize;
106 gst_mxf_mux_pad_init (GstMXFMuxPad * pad)
108 pad->adapter = gst_adapter_new ();
111 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
114 GST_STATIC_CAPS ("application/mxf")
122 #define gst_mxf_mux_parent_class parent_class
123 G_DEFINE_TYPE (GstMXFMux, gst_mxf_mux, GST_TYPE_AGGREGATOR);
124 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (mxfmux, "mxfmux", GST_RANK_PRIMARY,
125 GST_TYPE_MXF_MUX, mxf_element_init (plugin));
127 static void gst_mxf_mux_finalize (GObject * object);
129 static GstFlowReturn gst_mxf_mux_aggregate (GstAggregator * aggregator,
131 static gboolean gst_mxf_mux_stop (GstAggregator * aggregator);
133 static gboolean gst_mxf_mux_src_event (GstAggregator * aggregator,
135 static gboolean gst_mxf_mux_sink_event (GstAggregator * aggregator,
136 GstAggregatorPad * aggpad, GstEvent * event);
137 static GstAggregatorPad *gst_mxf_mux_create_new_pad (GstAggregator * aggregator,
138 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
140 static void gst_mxf_mux_reset (GstMXFMux * mux);
143 gst_mxf_mux_push (GstMXFMux * mux, GstBuffer * buf)
145 guint size = gst_buffer_get_size (buf);
148 ret = gst_aggregator_finish_buffer (GST_AGGREGATOR (mux), buf);
155 gst_mxf_mux_class_init (GstMXFMuxClass * klass)
157 GObjectClass *gobject_class;
158 GstElementClass *gstelement_class;
159 GstAggregatorClass *gstaggregator_class;
160 const GstPadTemplate **p;
162 GST_DEBUG_CATEGORY_INIT (mxfmux_debug, "mxfmux", 0, "MXF muxer");
164 gobject_class = (GObjectClass *) klass;
165 gstelement_class = (GstElementClass *) klass;
166 gstaggregator_class = (GstAggregatorClass *) klass;
168 gobject_class->finalize = gst_mxf_mux_finalize;
170 gstaggregator_class->create_new_pad =
171 GST_DEBUG_FUNCPTR (gst_mxf_mux_create_new_pad);
172 gstaggregator_class->src_event = GST_DEBUG_FUNCPTR (gst_mxf_mux_src_event);
173 gstaggregator_class->sink_event = GST_DEBUG_FUNCPTR (gst_mxf_mux_sink_event);
174 gstaggregator_class->stop = GST_DEBUG_FUNCPTR (gst_mxf_mux_stop);
175 gstaggregator_class->aggregate = GST_DEBUG_FUNCPTR (gst_mxf_mux_aggregate);
177 gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
178 &src_templ, GST_TYPE_MXF_MUX_PAD);
180 p = mxf_essence_element_writer_get_pad_templates ();
182 gst_element_class_add_pad_template (gstelement_class,
183 (GstPadTemplate *) gst_object_ref (GST_OBJECT (*p)));
187 gst_element_class_set_static_metadata (gstelement_class, "MXF muxer",
189 "Muxes video/audio streams into a MXF stream",
190 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
192 gst_type_mark_as_plugin_api (GST_TYPE_MXF_MUX_PAD, 0);
196 gst_mxf_mux_init (GstMXFMux * mux)
198 mux->index_table = g_array_new (FALSE, FALSE, sizeof (MXFIndexTableSegment));
199 gst_mxf_mux_reset (mux);
203 gst_mxf_mux_finalize (GObject * object)
205 GstMXFMux *mux = GST_MXF_MUX (object);
207 gst_mxf_mux_reset (mux);
210 g_hash_table_destroy (mux->metadata);
211 mux->metadata = NULL;
212 g_list_free (mux->metadata_list);
213 mux->metadata_list = NULL;
216 if (mux->index_table) {
218 for (n = 0; n < mux->index_table->len; ++n)
219 g_free (g_array_index (mux->index_table, MXFIndexTableSegment,
221 g_array_free (mux->index_table, TRUE);
222 mux->index_table = NULL;
225 G_OBJECT_CLASS (parent_class)->finalize (object);
229 gst_mxf_mux_reset (GstMXFMux * mux)
234 GST_OBJECT_LOCK (mux);
235 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
236 GstMXFMuxPad *pad = l->data;
238 gst_adapter_clear (pad->adapter);
239 g_free (pad->mapping_data);
240 pad->mapping_data = NULL;
243 pad->last_timestamp = 0;
244 pad->descriptor = NULL;
245 pad->have_complete_edit_unit = FALSE;
247 pad->source_package = NULL;
248 pad->source_track = NULL;
250 GST_OBJECT_UNLOCK (mux);
252 mux->state = GST_MXF_MUX_STATE_HEADER;
255 g_hash_table_destroy (mux->metadata);
257 g_list_free (mux->metadata_list);
258 mux->metadata_list = NULL;
260 mux->metadata = mxf_metadata_hash_table_new ();
262 mxf_partition_pack_reset (&mux->partition);
263 mxf_primer_pack_reset (&mux->primer);
264 memset (&mux->min_edit_rate, 0, sizeof (MXFFraction));
265 mux->last_gc_timestamp = 0;
266 mux->last_gc_position = 0;
269 if (mux->index_table)
270 for (n = 0; n < mux->index_table->len; ++n)
271 g_free (g_array_index (mux->index_table, MXFIndexTableSegment,
273 g_array_set_size (mux->index_table, 0);
274 mux->current_index_pos = 0;
275 mux->last_keyframe_pos = 0;
279 gst_mxf_mux_src_event (GstAggregator * aggregator, GstEvent * event)
281 switch (GST_EVENT_TYPE (event)) {
283 /* disable seeking for now */
284 gst_event_unref (event);
287 return GST_AGGREGATOR_CLASS (parent_class)->src_event (aggregator, event);
291 g_assert_not_reached ();
295 gst_mxf_mux_set_caps (GstMXFMux * mux, GstMXFMuxPad * pad, GstCaps * caps)
298 MXFUUID d_instance_uid = { {0,} };
299 MXFMetadataFileDescriptor *old_descriptor = pad->descriptor;
302 GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps);
304 if (old_descriptor) {
305 memcpy (&d_instance_uid, &MXF_METADATA_BASE (old_descriptor)->instance_uid,
307 pad->descriptor = NULL;
308 g_free (pad->mapping_data);
309 pad->mapping_data = NULL;
313 pad->writer->get_descriptor (GST_PAD_PAD_TEMPLATE (pad), caps,
314 &pad->write_func, &pad->mapping_data);
316 if (!pad->descriptor) {
317 GST_ERROR_OBJECT (mux,
318 "Couldn't get descriptor for pad '%s' with caps %" GST_PTR_FORMAT,
319 GST_PAD_NAME (pad), caps);
323 if (mxf_uuid_is_zero (&d_instance_uid))
324 mxf_uuid_init (&d_instance_uid, mux->metadata);
326 memcpy (&MXF_METADATA_BASE (pad->descriptor)->instance_uid, &d_instance_uid,
329 if (old_descriptor) {
330 for (l = mux->metadata_list; l; l = l->next) {
331 MXFMetadataBase *tmp = l->data;
333 if (mxf_uuid_is_equal (&d_instance_uid, &tmp->instance_uid)) {
334 l->data = pad->descriptor;
339 mux->metadata_list = g_list_prepend (mux->metadata_list, pad->descriptor);
342 g_hash_table_replace (mux->metadata,
343 &MXF_METADATA_BASE (pad->descriptor)->instance_uid, pad->descriptor);
345 if (old_descriptor) {
346 if (mux->preface && mux->preface->content_storage &&
347 mux->preface->content_storage->packages) {
350 for (i = 0; i < mux->preface->content_storage->n_packages; i++) {
351 MXFMetadataSourcePackage *package;
353 if (!MXF_IS_METADATA_SOURCE_PACKAGE (mux->preface->
354 content_storage->packages[i]))
358 MXF_METADATA_SOURCE_PACKAGE (mux->preface->
359 content_storage->packages[i]);
361 if (!package->descriptor)
364 if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor)) {
365 MXFMetadataMultipleDescriptor *tmp =
366 MXF_METADATA_MULTIPLE_DESCRIPTOR (package->descriptor);
368 for (j = 0; j < tmp->n_sub_descriptors; j++) {
369 if (tmp->sub_descriptors[j] ==
370 MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
371 tmp->sub_descriptors[j] =
372 MXF_METADATA_GENERIC_DESCRIPTOR (pad->descriptor);
373 memcpy (&tmp->sub_descriptors_uids[j], &d_instance_uid, 16);
376 } else if (package->descriptor ==
377 MXF_METADATA_GENERIC_DESCRIPTOR (old_descriptor)) {
378 package->descriptor =
379 MXF_METADATA_GENERIC_DESCRIPTOR (pad->descriptor);
380 memcpy (&package->descriptor_uid, &d_instance_uid, 16);
390 gst_mxf_mux_sink_event (GstAggregator * aggregator,
391 GstAggregatorPad * aggpad, GstEvent * event)
393 GstMXFMux *mux = GST_MXF_MUX (aggregator);
396 switch (GST_EVENT_TYPE (event)) {
398 /* TODO: do something with the tags */
400 case GST_EVENT_CAPS:{
403 gst_event_parse_caps (event, &caps);
405 ret = gst_mxf_mux_set_caps (mux, GST_MXF_MUX_PAD (aggpad), caps);
413 /* now GstAggregator can take care of the rest, e.g. EOS */
416 GST_AGGREGATOR_CLASS (parent_class)->sink_event (aggregator, aggpad,
423 gst_mxf_mux_create_pad_name (GstPadTemplate * templ, guint id)
427 string = g_string_new (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
428 g_string_truncate (string, string->len - 2);
429 g_string_append_printf (string, "%u", id);
431 return g_string_free (string, FALSE);
434 static GstAggregatorPad *
435 gst_mxf_mux_create_new_pad (GstAggregator * aggregator,
436 GstPadTemplate * templ, const gchar * pad_name, const GstCaps * caps)
438 GstMXFMux *mux = GST_MXF_MUX (aggregator);
442 const MXFEssenceElementWriter *writer;
444 if (mux->state != GST_MXF_MUX_STATE_HEADER) {
445 GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
449 writer = mxf_essence_element_writer_find (templ);
451 GST_ERROR_OBJECT (mux, "Not our template");
454 pad_number = g_atomic_int_add ((gint *) & mux->n_pads, 1);
455 name = gst_mxf_mux_create_pad_name (templ, pad_number);
457 GST_DEBUG_OBJECT (mux, "Creating pad '%s'", name);
459 g_object_new (GST_TYPE_MXF_MUX_PAD, "name", name, "direction",
460 GST_PAD_SINK, "template", templ, NULL);
462 pad->last_timestamp = 0;
463 pad->writer = writer;
465 gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
467 return GST_AGGREGATOR_PAD (pad);
471 gst_mxf_mux_create_metadata (GstMXFMux * mux)
473 GstFlowReturn ret = GST_FLOW_OK;
477 GST_DEBUG_OBJECT (mux, "Creating MXF metadata");
479 GST_OBJECT_LOCK (mux);
481 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
482 GstMXFMuxPad *pad = l->data;
486 if (!pad || !pad->descriptor) {
487 GST_OBJECT_UNLOCK (mux);
488 return GST_FLOW_ERROR;
491 caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
493 GST_OBJECT_UNLOCK (mux);
494 return GST_FLOW_ERROR;
497 buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
498 if (pad->writer->update_descriptor)
499 pad->writer->update_descriptor (pad->descriptor,
500 caps, pad->mapping_data, buffer);
502 gst_buffer_unref (buffer);
503 gst_caps_unref (caps);
508 (MXFMetadataPreface *) g_object_new (MXF_TYPE_METADATA_PREFACE, NULL);
509 mxf_uuid_init (&MXF_METADATA_BASE (mux->preface)->instance_uid,
511 g_hash_table_insert (mux->metadata,
512 &MXF_METADATA_BASE (mux->preface)->instance_uid, mux->preface);
513 mux->metadata_list = g_list_prepend (mux->metadata_list, mux->preface);
515 mxf_timestamp_set_now (&mux->preface->last_modified_date);
516 mux->preface->version = 258;
517 mux->preface->object_model_version = 1;
519 mxf_op_set_generalized (&mux->preface->operational_pattern, MXF_OP_1a, TRUE,
522 tmp = g_array_new (FALSE, FALSE, sizeof (MXFUL));
523 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
524 GstMXFMuxPad *pad = l->data;
526 gboolean found = FALSE;
528 if (!pad || !pad->descriptor ||
529 mxf_ul_is_zero (&pad->descriptor->essence_container)) {
530 GST_OBJECT_UNLOCK (mux);
531 return GST_FLOW_ERROR;
534 for (i = 0; i < tmp->len; i++) {
535 if (mxf_ul_is_equal (&pad->descriptor->essence_container,
536 &g_array_index (tmp, MXFUL, i))) {
545 g_array_append_val (tmp, pad->descriptor->essence_container);
547 mux->preface->n_essence_containers = tmp->len;
548 mux->preface->essence_containers = (MXFUL *) g_array_free (tmp, FALSE);
550 /* This will later be used as UID for the material package */
551 mxf_uuid_init (&mux->preface->primary_package_uid, mux->metadata);
553 /* Identifications */
555 MXFMetadataIdentification *identification;
556 static const guint8 gst_uid[] = {
557 0xe5, 0xde, 0xcd, 0x04, 0x24, 0x90, 0x69, 0x18,
558 0x8a, 0xc9, 0xb5, 0xd7, 0x02, 0x58, 0x46, 0x78
560 guint major, minor, micro, nano;
562 mux->preface->n_identifications = 1;
563 mux->preface->identifications = g_new0 (MXFMetadataIdentification *, 1);
564 identification = mux->preface->identifications[0] =
565 (MXFMetadataIdentification *)
566 g_object_new (MXF_TYPE_METADATA_IDENTIFICATION, NULL);
568 mxf_uuid_init (&MXF_METADATA_BASE (identification)->instance_uid,
570 g_hash_table_insert (mux->metadata,
571 &MXF_METADATA_BASE (identification)->instance_uid, identification);
572 mux->metadata_list = g_list_prepend (mux->metadata_list, identification);
574 mxf_uuid_init (&identification->this_generation_uid, NULL);
576 identification->company_name = g_strdup ("GStreamer");
577 identification->product_name = g_strdup ("GStreamer Multimedia Framework");
579 gst_version (&major, &minor, µ, &nano);
580 identification->product_version.major = major;
581 identification->product_version.minor = minor;
582 identification->product_version.patch = micro;
583 identification->product_version.build = nano;
584 identification->product_version.release =
585 (nano == 0) ? 1 : (nano == 1) ? 2 : 4;
587 identification->version_string =
588 g_strdup_printf ("%u.%u.%u.%u", major, minor, micro, nano);
589 memcpy (&identification->product_uid, &gst_uid, 16);
591 memcpy (&identification->modification_date,
592 &mux->preface->last_modified_date, sizeof (MXFTimestamp));
593 memcpy (&identification->toolkit_version, &identification->product_version,
594 sizeof (MXFProductVersion));
596 #ifdef HAVE_SYS_UTSNAME_H
598 struct utsname sys_details;
600 if (uname (&sys_details) == 0) {
601 identification->platform = g_strdup_printf ("%s %s %s",
602 sys_details.sysname, sys_details.release, sys_details.machine);
607 #if defined(G_OS_WIN32)
608 if (identification->platform == NULL)
609 identification->platform = g_strdup ("Microsoft Windows");
610 #elif defined(G_OS_BEOS)
611 if (identification->platform == NULL)
612 identification->platform = g_strdup ("BEOS");
613 #elif defined(G_OS_UNIX)
614 if (identification->platform == NULL)
615 identification->platform = g_strdup ("Unix");
619 /* Content storage */
621 MXFMetadataContentStorage *cstorage;
624 cstorage = mux->preface->content_storage = (MXFMetadataContentStorage *)
625 g_object_new (MXF_TYPE_METADATA_CONTENT_STORAGE, NULL);
626 mxf_uuid_init (&MXF_METADATA_BASE (cstorage)->instance_uid, mux->metadata);
627 g_hash_table_insert (mux->metadata,
628 &MXF_METADATA_BASE (cstorage)->instance_uid, cstorage);
629 mux->metadata_list = g_list_prepend (mux->metadata_list, cstorage);
631 cstorage->n_packages = 2;
632 cstorage->packages = g_new0 (MXFMetadataGenericPackage *, 2);
636 MXFMetadataSourcePackage *p;
638 cstorage->packages[1] = (MXFMetadataGenericPackage *)
639 g_object_new (MXF_TYPE_METADATA_SOURCE_PACKAGE, NULL);
640 mxf_uuid_init (&MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
642 g_hash_table_insert (mux->metadata,
643 &MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
644 cstorage->packages[1]);
646 g_list_prepend (mux->metadata_list, cstorage->packages[1]);
647 p = (MXFMetadataSourcePackage *) cstorage->packages[1];
649 mxf_umid_init (&p->parent.package_uid);
650 p->parent.name = g_strdup ("Source package");
651 memcpy (&p->parent.package_creation_date,
652 &mux->preface->last_modified_date, sizeof (MXFTimestamp));
653 memcpy (&p->parent.package_modified_date,
654 &mux->preface->last_modified_date, sizeof (MXFTimestamp));
656 p->parent.n_tracks = GST_ELEMENT_CAST (mux)->numsinkpads + 1;
657 p->parent.tracks = g_new0 (MXFMetadataTrack *, p->parent.n_tracks);
659 if (p->parent.n_tracks > 2) {
660 MXFMetadataMultipleDescriptor *d;
662 p->descriptor = (MXFMetadataGenericDescriptor *)
663 g_object_new (MXF_TYPE_METADATA_MULTIPLE_DESCRIPTOR, NULL);
664 d = (MXFMetadataMultipleDescriptor *) p->descriptor;
665 d->n_sub_descriptors = p->parent.n_tracks - 1;
667 g_new0 (MXFMetadataGenericDescriptor *, p->parent.n_tracks - 1);
669 mxf_uuid_init (&MXF_METADATA_BASE (d)->instance_uid, mux->metadata);
670 g_hash_table_insert (mux->metadata,
671 &MXF_METADATA_BASE (d)->instance_uid, d);
672 mux->metadata_list = g_list_prepend (mux->metadata_list, d);
682 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
683 GstMXFMuxPad *pad = l->data;
684 MXFMetadataTimelineTrack *track;
685 MXFMetadataSequence *sequence;
686 MXFMetadataSourceClip *clip;
690 p->parent.tracks[n] = (MXFMetadataTrack *)
691 g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
692 track = (MXFMetadataTimelineTrack *) p->parent.tracks[n];
693 mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
695 g_hash_table_insert (mux->metadata,
696 &MXF_METADATA_BASE (track)->instance_uid, track);
697 mux->metadata_list = g_list_prepend (mux->metadata_list, track);
699 caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
700 buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
701 track->parent.track_id = n + 1;
702 track->parent.track_number =
703 pad->writer->get_track_number_template (pad->descriptor,
704 caps, pad->mapping_data);
706 /* FIXME: All tracks in a source package must have the same edit
707 * rate! This means that if we have different edit rates, we need to
708 * make them different source packages and essence containers with
709 * a different BodySID */
710 pad->writer->get_edit_rate (pad->descriptor,
711 caps, pad->mapping_data, buffer, p, track, &track->edit_rate);
713 gst_buffer_unref (buffer);
714 gst_caps_unref (caps);
716 sequence = track->parent.sequence = (MXFMetadataSequence *)
717 g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
718 mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
720 g_hash_table_insert (mux->metadata,
721 &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
722 mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
724 memcpy (&sequence->data_definition, &pad->writer->data_definition,
727 sequence->n_structural_components = 1;
728 sequence->structural_components =
729 g_new0 (MXFMetadataStructuralComponent *, 1);
731 clip = (MXFMetadataSourceClip *)
732 g_object_new (MXF_TYPE_METADATA_SOURCE_CLIP, NULL);
733 sequence->structural_components[0] =
734 (MXFMetadataStructuralComponent *) clip;
735 mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
737 g_hash_table_insert (mux->metadata,
738 &MXF_METADATA_BASE (clip)->instance_uid, clip);
739 mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
741 memcpy (&clip->parent.data_definition, &sequence->data_definition,
743 clip->start_position = 0;
745 pad->source_package = p;
746 pad->source_track = track;
747 pad->descriptor->linked_track_id = n + 1;
748 if (p->parent.n_tracks == 2) {
749 p->descriptor = (MXFMetadataGenericDescriptor *) pad->descriptor;
751 MXF_METADATA_MULTIPLE_DESCRIPTOR (p->
752 descriptor)->sub_descriptors[n - 1] =
753 (MXFMetadataGenericDescriptor *) pad->descriptor;
761 /* Material package */
763 MXFMetadataMaterialPackage *p;
764 MXFFraction min_edit_rate = { 0, 0 };
765 gdouble min_edit_rate_d = G_MAXDOUBLE;
767 cstorage->packages[0] = (MXFMetadataGenericPackage *)
768 g_object_new (MXF_TYPE_METADATA_MATERIAL_PACKAGE, NULL);
769 memcpy (&MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
770 &mux->preface->primary_package_uid, 16);
771 g_hash_table_insert (mux->metadata,
772 &MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
773 cstorage->packages[0]);
775 g_list_prepend (mux->metadata_list, cstorage->packages[0]);
776 p = (MXFMetadataMaterialPackage *) cstorage->packages[0];
778 mxf_umid_init (&p->package_uid);
779 p->name = g_strdup ("Material package");
780 memcpy (&p->package_creation_date, &mux->preface->last_modified_date,
781 sizeof (MXFTimestamp));
782 memcpy (&p->package_modified_date, &mux->preface->last_modified_date,
783 sizeof (MXFTimestamp));
785 p->n_tracks = GST_ELEMENT_CAST (mux)->numsinkpads + 1;
786 p->tracks = g_new0 (MXFMetadataTrack *, p->n_tracks);
794 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
795 GstMXFMuxPad *pad = l->data;
798 MXFMetadataSourcePackage *source_package;
799 MXFMetadataTimelineTrack *track, *source_track;
800 MXFMetadataSequence *sequence;
801 MXFMetadataSourceClip *clip;
803 source_package = MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
805 MXF_METADATA_TIMELINE_TRACK (source_package->parent.tracks[n]);
807 p->tracks[n] = (MXFMetadataTrack *)
808 g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
809 track = (MXFMetadataTimelineTrack *) p->tracks[n];
810 mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
812 g_hash_table_insert (mux->metadata,
813 &MXF_METADATA_BASE (track)->instance_uid, track);
814 mux->metadata_list = g_list_prepend (mux->metadata_list, track);
816 track->parent.track_id = n + 1;
817 track->parent.track_number = 0;
819 caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
820 buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
821 pad->writer->get_edit_rate (pad->descriptor,
822 caps, pad->mapping_data,
823 buffer, source_package, source_track, &track->edit_rate);
825 gst_buffer_unref (buffer);
826 gst_caps_unref (caps);
828 if (track->edit_rate.n != source_track->edit_rate.n ||
829 track->edit_rate.d != source_track->edit_rate.d) {
830 memcpy (&source_track->edit_rate, &track->edit_rate,
831 sizeof (MXFFraction));
834 if (track->edit_rate.d <= 0 || track->edit_rate.n <= 0) {
835 GST_ERROR_OBJECT (mux, "Invalid edit rate");
836 GST_OBJECT_UNLOCK (mux);
837 return GST_FLOW_ERROR;
840 if (min_edit_rate_d >
841 ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d)) {
843 ((gdouble) track->edit_rate.n) / ((gdouble) track->edit_rate.d);
844 memcpy (&min_edit_rate, &track->edit_rate, sizeof (MXFFraction));
847 sequence = track->parent.sequence = (MXFMetadataSequence *)
848 g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
849 mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
851 g_hash_table_insert (mux->metadata,
852 &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
853 mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
855 memcpy (&sequence->data_definition, &pad->writer->data_definition,
857 sequence->n_structural_components = 1;
858 sequence->structural_components =
859 g_new0 (MXFMetadataStructuralComponent *, 1);
861 clip = (MXFMetadataSourceClip *)
862 g_object_new (MXF_TYPE_METADATA_SOURCE_CLIP, NULL);
863 sequence->structural_components[0] =
864 (MXFMetadataStructuralComponent *) clip;
865 mxf_uuid_init (&MXF_METADATA_BASE (clip)->instance_uid,
867 g_hash_table_insert (mux->metadata,
868 &MXF_METADATA_BASE (clip)->instance_uid, clip);
869 mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
871 memcpy (&clip->parent.data_definition, &sequence->data_definition,
873 clip->start_position = 0;
875 memcpy (&clip->source_package_id, &cstorage->packages[1]->package_uid,
877 clip->source_track_id = n + 1;
885 MXFMetadataTimelineTrack *track;
886 MXFMetadataSequence *sequence;
887 MXFMetadataTimecodeComponent *component;
889 p->tracks[n] = (MXFMetadataTrack *)
890 g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
891 track = (MXFMetadataTimelineTrack *) p->tracks[n];
892 mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid,
894 g_hash_table_insert (mux->metadata,
895 &MXF_METADATA_BASE (track)->instance_uid, track);
896 mux->metadata_list = g_list_prepend (mux->metadata_list, track);
898 track->parent.track_id = n + 1;
899 track->parent.track_number = 0;
900 track->parent.track_name = g_strdup ("Timecode track");
901 /* FIXME: Is this correct? */
902 memcpy (&track->edit_rate, &min_edit_rate, sizeof (MXFFraction));
904 sequence = track->parent.sequence = (MXFMetadataSequence *)
905 g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
906 mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
908 g_hash_table_insert (mux->metadata,
909 &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
910 mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
912 memcpy (&sequence->data_definition,
913 mxf_metadata_track_identifier_get
914 (MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE), 16);
916 sequence->n_structural_components = 1;
917 sequence->structural_components =
918 g_new0 (MXFMetadataStructuralComponent *, 1);
920 component = (MXFMetadataTimecodeComponent *)
921 g_object_new (MXF_TYPE_METADATA_TIMECODE_COMPONENT, NULL);
922 sequence->structural_components[0] =
923 (MXFMetadataStructuralComponent *) component;
924 mxf_uuid_init (&MXF_METADATA_BASE (component)->instance_uid,
926 g_hash_table_insert (mux->metadata,
927 &MXF_METADATA_BASE (component)->instance_uid, component);
928 mux->metadata_list = g_list_prepend (mux->metadata_list, component);
930 memcpy (&component->parent.data_definition,
931 &sequence->data_definition, 16);
933 component->start_timecode = 0;
934 if (track->edit_rate.d == 0)
935 component->rounded_timecode_base = 1;
937 component->rounded_timecode_base =
938 (((gdouble) track->edit_rate.n) /
939 ((gdouble) track->edit_rate.d) + 0.5);
940 /* TODO: drop frame */
943 memcpy (&mux->min_edit_rate, &min_edit_rate, sizeof (MXFFraction));
949 MXFMetadataSourcePackage *p;
950 MXFMetadataTimelineTrack *track;
951 MXFMetadataSequence *sequence;
952 MXFMetadataTimecodeComponent *component;
955 p = (MXFMetadataSourcePackage *) cstorage->packages[1];
957 p->parent.tracks[n] = (MXFMetadataTrack *)
958 g_object_new (MXF_TYPE_METADATA_TIMELINE_TRACK, NULL);
959 track = (MXFMetadataTimelineTrack *) p->parent.tracks[n];
960 mxf_uuid_init (&MXF_METADATA_BASE (track)->instance_uid, mux->metadata);
961 g_hash_table_insert (mux->metadata,
962 &MXF_METADATA_BASE (track)->instance_uid, track);
963 mux->metadata_list = g_list_prepend (mux->metadata_list, track);
965 track->parent.track_id = n + 1;
966 track->parent.track_number = 0;
967 track->parent.track_name = g_strdup ("Timecode track");
968 /* FIXME: Is this correct? */
969 memcpy (&track->edit_rate, &mux->min_edit_rate, sizeof (MXFFraction));
971 sequence = track->parent.sequence = (MXFMetadataSequence *)
972 g_object_new (MXF_TYPE_METADATA_SEQUENCE, NULL);
973 mxf_uuid_init (&MXF_METADATA_BASE (sequence)->instance_uid,
975 g_hash_table_insert (mux->metadata,
976 &MXF_METADATA_BASE (sequence)->instance_uid, sequence);
977 mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
979 memcpy (&sequence->data_definition,
980 mxf_metadata_track_identifier_get
981 (MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE), 16);
983 sequence->n_structural_components = 1;
984 sequence->structural_components =
985 g_new0 (MXFMetadataStructuralComponent *, 1);
987 component = (MXFMetadataTimecodeComponent *)
988 g_object_new (MXF_TYPE_METADATA_TIMECODE_COMPONENT, NULL);
989 sequence->structural_components[0] =
990 (MXFMetadataStructuralComponent *) component;
991 mxf_uuid_init (&MXF_METADATA_BASE (component)->instance_uid,
993 g_hash_table_insert (mux->metadata,
994 &MXF_METADATA_BASE (component)->instance_uid, component);
995 mux->metadata_list = g_list_prepend (mux->metadata_list, component);
997 memcpy (&component->parent.data_definition,
998 &sequence->data_definition, 16);
1000 component->start_timecode = 0;
1001 if (track->edit_rate.d == 0)
1002 component->rounded_timecode_base = 1;
1004 component->rounded_timecode_base =
1005 (((gdouble) track->edit_rate.n) /
1006 ((gdouble) track->edit_rate.d) + 0.5);
1007 /* TODO: drop frame */
1011 for (i = 1; i < cstorage->packages[1]->n_tracks; i++) {
1012 MXFMetadataTrack *track = cstorage->packages[1]->tracks[i];
1017 if ((track->track_number & 0x00ff00ff) != 0)
1020 templ = track->track_number;
1023 for (j = 1; j < cstorage->packages[1]->n_tracks; j++) {
1024 MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
1026 if (tmp->track_number == templ) {
1032 for (j = 1; j < cstorage->packages[1]->n_tracks; j++) {
1033 MXFMetadataTrack *tmp = cstorage->packages[1]->tracks[j];
1035 if (tmp->track_number == templ) {
1037 tmp->track_number |= (n_type << 16) | (n);
1042 cstorage->n_essence_container_data = 1;
1043 cstorage->essence_container_data =
1044 g_new0 (MXFMetadataEssenceContainerData *, 1);
1045 cstorage->essence_container_data[0] = (MXFMetadataEssenceContainerData *)
1046 g_object_new (MXF_TYPE_METADATA_ESSENCE_CONTAINER_DATA, NULL);
1047 mxf_uuid_init (&MXF_METADATA_BASE (cstorage->essence_container_data[0])->
1048 instance_uid, mux->metadata);
1049 g_hash_table_insert (mux->metadata,
1050 &MXF_METADATA_BASE (cstorage->essence_container_data[0])->instance_uid,
1051 cstorage->essence_container_data[0]);
1052 mux->metadata_list =
1053 g_list_prepend (mux->metadata_list,
1054 cstorage->essence_container_data[0]);
1056 cstorage->essence_container_data[0]->linked_package =
1057 MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
1058 cstorage->essence_container_data[0]->index_sid = 2;
1059 cstorage->essence_container_data[0]->body_sid = 1;
1062 /* Sort descriptors at the correct places */
1065 GList *descriptors = NULL;
1067 for (l = mux->metadata_list; l; l = l->next) {
1068 MXFMetadataBase *m = l->data;
1070 if (MXF_IS_METADATA_GENERIC_DESCRIPTOR (m)
1071 && !MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m)) {
1073 l->prev->next = NULL;
1079 g_assert (descriptors != NULL);
1081 for (l = mux->metadata_list; l; l = l->next) {
1082 MXFMetadataBase *m = l->data;
1085 if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m) ||
1086 MXF_IS_METADATA_SOURCE_PACKAGE (m)) {
1088 l->prev = g_list_last (descriptors);
1089 s->next = descriptors;
1090 descriptors->prev = s;
1097 GST_OBJECT_UNLOCK (mux);
1099 mux->metadata_list = g_list_reverse (mux->metadata_list);
1104 static GstFlowReturn
1105 gst_mxf_mux_init_partition_pack (GstMXFMux * mux)
1110 mxf_partition_pack_reset (&mux->partition);
1111 mux->partition.type = MXF_PARTITION_PACK_HEADER;
1112 mux->partition.closed = mux->partition.complete = FALSE;
1113 mux->partition.major_version = 0x0001;
1114 mux->partition.minor_version = 0x0002;
1115 mux->partition.kag_size = 1;
1116 mux->partition.this_partition = 0;
1117 mux->partition.prev_partition = 0;
1118 mux->partition.footer_partition = 0;
1119 mux->partition.header_byte_count = 0;
1120 mux->partition.index_byte_count = 0;
1121 mux->partition.index_sid = 0;
1122 mux->partition.body_offset = 0;
1123 mux->partition.body_sid = 0;
1125 memcpy (&mux->partition.operational_pattern,
1126 &mux->preface->operational_pattern, 16);
1128 GST_OBJECT_LOCK (mux);
1129 mux->partition.n_essence_containers = GST_ELEMENT_CAST (mux)->numsinkpads;
1130 mux->partition.essence_containers =
1131 g_new0 (MXFUL, mux->partition.n_essence_containers);
1133 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1134 GstMXFMuxPad *pad = l->data;
1136 gboolean found = FALSE;
1138 for (j = 0; j <= i; j++) {
1139 if (mxf_ul_is_equal (&pad->descriptor->essence_container,
1140 &mux->partition.essence_containers[j])) {
1149 memcpy (&mux->partition.essence_containers[i],
1150 &pad->descriptor->essence_container, 16);
1153 mux->partition.n_essence_containers = i;
1154 GST_OBJECT_UNLOCK (mux);
1159 static GstFlowReturn
1160 gst_mxf_mux_write_header_metadata (GstMXFMux * mux)
1162 GstFlowReturn ret = GST_FLOW_OK;
1164 GList *buffers = NULL;
1167 guint64 header_byte_count = 0;
1169 for (l = mux->metadata_list; l; l = l->next) {
1171 buf = mxf_metadata_base_to_buffer (m, &mux->primer);
1172 header_byte_count += gst_buffer_get_size (buf);
1173 buffers = g_list_prepend (buffers, buf);
1176 buffers = g_list_reverse (buffers);
1177 buf = mxf_primer_pack_to_buffer (&mux->primer);
1178 header_byte_count += gst_buffer_get_size (buf);
1179 buffers = g_list_prepend (buffers, buf);
1181 mux->partition.header_byte_count = header_byte_count;
1182 buf = mxf_partition_pack_to_buffer (&mux->partition);
1183 if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1184 GST_ERROR_OBJECT (mux, "Failed pushing partition: %s",
1185 gst_flow_get_name (ret));
1186 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
1187 g_list_free (buffers);
1191 for (l = buffers; l; l = l->next) {
1194 if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
1195 GST_ERROR_OBJECT (mux, "Failed pushing buffer: %s",
1196 gst_flow_get_name (ret));
1197 g_list_foreach (l, (GFunc) gst_mini_object_unref, NULL);
1198 g_list_free (buffers);
1203 g_list_free (buffers);
1208 static const guint8 _gc_essence_element_ul[] = {
1209 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x02, 0x01, 0x01,
1210 0x0d, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00
1213 static GstFlowReturn
1214 gst_mxf_mux_handle_buffer (GstMXFMux * mux, GstMXFMuxPad * pad)
1216 GstBuffer *buf = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
1217 GstBuffer *outbuf = NULL;
1220 GstFlowReturn ret = GST_FLOW_OK;
1221 guint8 slen, ber[9];
1222 gboolean flush = gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))
1223 && !pad->have_complete_edit_unit && buf == NULL;
1224 gboolean is_keyframe = buf ?
1225 !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) : TRUE;
1226 GstClockTime pts = buf ? GST_BUFFER_PTS (buf) : GST_CLOCK_TIME_NONE;
1227 GstClockTime dts = buf ? GST_BUFFER_DTS (buf) : GST_CLOCK_TIME_NONE;
1229 if (pad->have_complete_edit_unit) {
1230 GST_DEBUG_OBJECT (pad,
1231 "Handling remaining buffer for track %u at position %" G_GINT64_FORMAT,
1232 pad->source_track->parent.track_id, pad->pos);
1234 gst_buffer_unref (buf);
1236 } else if (!flush) {
1238 gst_buffer_unref (buf);
1239 buf = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (pad));
1243 GST_DEBUG_OBJECT (pad,
1244 "Handling buffer of size %" G_GSIZE_FORMAT " for track %u at position %"
1245 G_GINT64_FORMAT, gst_buffer_get_size (buf),
1246 pad->source_track->parent.track_id, pad->pos);
1249 GST_DEBUG_OBJECT (pad,
1250 "Flushing for track %u at position %" G_GINT64_FORMAT,
1251 pad->source_track->parent.track_id, pad->pos);
1254 ret = pad->write_func (buf, pad->mapping_data, pad->adapter, &outbuf, flush);
1255 if (ret != GST_FLOW_OK && ret != GST_FLOW_CUSTOM_SUCCESS) {
1256 GST_ERROR_OBJECT (pad,
1257 "Failed handling buffer for track %u, reason %s",
1258 pad->source_track->parent.track_id, gst_flow_get_name (ret));
1262 if (ret == GST_FLOW_CUSTOM_SUCCESS) {
1263 pad->have_complete_edit_unit = TRUE;
1266 pad->have_complete_edit_unit = FALSE;
1273 /* We currently only index the first essence stream */
1274 if (pad == (GstMXFMuxPad *) GST_ELEMENT_CAST (mux)->sinkpads->data) {
1275 MXFIndexTableSegment *segment;
1276 const gint max_segment_size = G_MAXUINT16 / 11;
1278 if (mux->index_table->len == 0 ||
1279 g_array_index (mux->index_table, MXFIndexTableSegment,
1280 mux->current_index_pos).index_duration >= max_segment_size) {
1282 if (mux->index_table->len > 0)
1283 mux->current_index_pos++;
1285 if (mux->index_table->len <= mux->current_index_pos) {
1286 MXFIndexTableSegment s;
1288 memset (&segment, 0, sizeof (segment));
1290 mxf_uuid_init (&s.instance_id, mux->metadata);
1291 memcpy (&s.index_edit_rate, &pad->source_track->edit_rate,
1292 sizeof (s.index_edit_rate));
1293 if (mux->index_table->len > 0)
1294 s.index_start_position =
1295 g_array_index (mux->index_table, MXFIndexTableSegment,
1296 mux->index_table->len - 1).index_start_position;
1298 s.index_start_position = 0;
1299 s.index_duration = 0;
1300 s.edit_unit_byte_count = 0;
1302 mux->preface->content_storage->essence_container_data[0]->index_sid;
1304 mux->preface->content_storage->essence_container_data[0]->body_sid;
1306 s.pos_table_count = 0;
1307 s.n_delta_entries = 0;
1308 s.delta_entries = NULL;
1309 s.n_index_entries = 0;
1310 s.index_entries = g_new0 (MXFIndexEntry, max_segment_size);
1311 g_array_append_val (mux->index_table, s);
1315 &g_array_index (mux->index_table, MXFIndexTableSegment,
1316 mux->current_index_pos);
1318 if (dts != GST_CLOCK_TIME_NONE && pts != GST_CLOCK_TIME_NONE) {
1320 guint64 pts_index_pos, pts_segment_pos;
1321 gint64 index_pos_diff;
1322 MXFIndexTableSegment *pts_segment;
1325 gst_segment_to_running_time (&pad->parent.segment, GST_FORMAT_TIME,
1328 gst_util_uint64_scale_round (pts, pad->source_track->edit_rate.n,
1329 pad->source_track->edit_rate.d * GST_SECOND);
1331 index_pos_diff = pts_pos - pad->pos;
1332 pts_index_pos = mux->current_index_pos;
1333 pts_segment_pos = segment->n_index_entries;
1334 if (index_pos_diff >= 0) {
1335 while (pts_segment_pos + index_pos_diff >= max_segment_size) {
1336 index_pos_diff -= max_segment_size - pts_segment_pos;
1337 pts_segment_pos = 0;
1340 if (pts_index_pos >= mux->index_table->len) {
1341 MXFIndexTableSegment s;
1343 memset (&segment, 0, sizeof (segment));
1345 mxf_uuid_init (&s.instance_id, mux->metadata);
1346 memcpy (&s.index_edit_rate, &pad->source_track->edit_rate,
1347 sizeof (s.index_edit_rate));
1348 if (mux->index_table->len > 0)
1349 s.index_start_position =
1350 g_array_index (mux->index_table, MXFIndexTableSegment,
1351 mux->index_table->len - 1).index_start_position;
1353 s.index_start_position = 0;
1354 s.index_duration = 0;
1355 s.edit_unit_byte_count = 0;
1357 mux->preface->content_storage->
1358 essence_container_data[0]->index_sid;
1360 mux->preface->content_storage->
1361 essence_container_data[0]->body_sid;
1363 s.pos_table_count = 0;
1364 s.n_delta_entries = 0;
1365 s.delta_entries = NULL;
1366 s.n_index_entries = 0;
1367 s.index_entries = g_new0 (MXFIndexEntry, max_segment_size);
1368 g_array_append_val (mux->index_table, s);
1372 while (pts_segment_pos + index_pos_diff <= 0) {
1373 if (pts_index_pos == 0) {
1374 pts_index_pos = G_MAXUINT64;
1377 index_pos_diff += pts_segment_pos;
1378 pts_segment_pos = max_segment_size;
1382 if (pts_index_pos != G_MAXUINT64) {
1383 g_assert (index_pos_diff < 127 && index_pos_diff >= -127);
1385 &g_array_index (mux->index_table, MXFIndexTableSegment,
1387 pts_segment->index_entries[pts_segment_pos +
1388 index_pos_diff].temporal_offset = -index_pos_diff;
1392 /* Leave temporal offset initialized at 0, above code will set it as necessary */
1395 mux->last_keyframe_pos = pad->pos;
1396 segment->index_entries[segment->n_index_entries].key_frame_offset =
1397 MIN (pad->pos - mux->last_keyframe_pos, 127);
1398 segment->index_entries[segment->n_index_entries].flags = is_keyframe ? 0x80 : 0x20; /* FIXME: Need to distinguish all the cases */
1399 segment->index_entries[segment->n_index_entries].stream_offset =
1400 mux->partition.body_offset;
1402 segment->n_index_entries++;
1403 segment->index_duration++;
1406 buf_size = gst_buffer_get_size (buf);
1407 slen = mxf_ber_encode_size (buf_size, ber);
1408 outbuf = gst_buffer_new_and_alloc (16 + slen);
1409 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1410 memcpy (map.data, _gc_essence_element_ul, 16);
1411 GST_WRITE_UINT32_BE (map.data + 12, pad->source_track->parent.track_number);
1412 memcpy (map.data + 16, ber, slen);
1413 gst_buffer_unmap (outbuf, &map);
1414 outbuf = gst_buffer_append (outbuf, buf);
1416 GST_DEBUG_OBJECT (pad,
1417 "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u",
1418 gst_buffer_get_size (outbuf), pad->source_track->parent.track_id);
1420 mux->partition.body_offset += gst_buffer_get_size (outbuf);
1421 if ((ret = gst_mxf_mux_push (mux, outbuf)) != GST_FLOW_OK) {
1422 GST_ERROR_OBJECT (pad,
1423 "Failed pushing buffer for track %u, reason %s",
1424 pad->source_track->parent.track_id, gst_flow_get_name (ret));
1429 pad->last_timestamp =
1430 gst_util_uint64_scale (GST_SECOND * pad->pos,
1431 pad->source_track->edit_rate.d, pad->source_track->edit_rate.n);
1436 static GstFlowReturn
1437 gst_mxf_mux_write_body_partition (GstMXFMux * mux)
1441 mux->partition.type = MXF_PARTITION_PACK_BODY;
1442 mux->partition.closed = TRUE;
1443 mux->partition.complete = TRUE;
1444 mux->partition.this_partition = mux->offset;
1445 mux->partition.prev_partition = 0;
1446 mux->partition.footer_partition = 0;
1447 mux->partition.header_byte_count = 0;
1448 mux->partition.index_byte_count = 0;
1449 mux->partition.index_sid = 0;
1450 mux->partition.body_offset = 0;
1451 mux->partition.body_sid =
1452 mux->preface->content_storage->essence_container_data[0]->body_sid;
1454 buf = mxf_partition_pack_to_buffer (&mux->partition);
1455 return gst_mxf_mux_push (mux, buf);
1458 static GstFlowReturn
1459 gst_mxf_mux_handle_eos (GstMXFMux * mux)
1462 gboolean have_data = FALSE;
1466 GstMXFMuxPad *best = NULL;
1470 GST_OBJECT_LOCK (mux);
1471 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1472 GstMXFMuxPad *pad = l->data;
1474 gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
1476 GstClockTime next_gc_timestamp =
1477 gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1478 mux->min_edit_rate.d, mux->min_edit_rate.n);
1480 if (pad->have_complete_edit_unit ||
1481 gst_adapter_available (pad->adapter) > 0 || buffer) {
1483 if (pad->last_timestamp < next_gc_timestamp) {
1484 best = gst_object_ref (pad);
1486 gst_buffer_unref (buffer);
1491 gst_buffer_unref (buffer);
1493 if (have_data && !l->next) {
1494 mux->last_gc_position++;
1495 mux->last_gc_timestamp = next_gc_timestamp;
1499 GST_OBJECT_UNLOCK (mux);
1502 gst_mxf_mux_handle_buffer (mux, best);
1503 gst_object_unref (best);
1506 } while (have_data);
1508 mux->last_gc_position++;
1509 mux->last_gc_timestamp =
1510 gst_util_uint64_scale (mux->last_gc_position * GST_SECOND,
1511 mux->min_edit_rate.d, mux->min_edit_rate.n);
1513 /* Update essence track durations */
1514 GST_OBJECT_LOCK (mux);
1515 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1516 GstMXFMuxPad *pad = l->data;
1519 /* Update durations */
1520 pad->source_track->parent.sequence->duration = pad->pos;
1521 MXF_METADATA_SOURCE_CLIP (pad->source_track->parent.
1522 sequence->structural_components[0])->parent.duration = pad->pos;
1523 for (i = 0; i < mux->preface->content_storage->packages[0]->n_tracks; i++) {
1524 MXFMetadataTimelineTrack *track;
1526 if (!MXF_IS_METADATA_TIMELINE_TRACK (mux->preface->
1527 content_storage->packages[0]->tracks[i])
1528 || !MXF_IS_METADATA_SOURCE_CLIP (mux->preface->
1529 content_storage->packages[0]->tracks[i]->sequence->
1530 structural_components[0]))
1534 MXF_METADATA_TIMELINE_TRACK (mux->preface->
1535 content_storage->packages[0]->tracks[i]);
1536 if (MXF_METADATA_SOURCE_CLIP (track->parent.
1537 sequence->structural_components[0])->source_track_id ==
1538 pad->source_track->parent.track_id) {
1539 track->parent.sequence->structural_components[0]->duration = pad->pos;
1540 track->parent.sequence->duration = pad->pos;
1544 GST_OBJECT_UNLOCK (mux);
1546 /* Update timecode track duration */
1548 MXFMetadataTimelineTrack *track =
1549 MXF_METADATA_TIMELINE_TRACK (mux->preface->
1550 content_storage->packages[0]->tracks[0]);
1551 MXFMetadataSequence *sequence = track->parent.sequence;
1552 MXFMetadataTimecodeComponent *component =
1553 MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1555 sequence->duration = mux->last_gc_position;
1556 component->parent.duration = mux->last_gc_position;
1560 MXFMetadataTimelineTrack *track =
1561 MXF_METADATA_TIMELINE_TRACK (mux->preface->
1562 content_storage->packages[1]->tracks[0]);
1563 MXFMetadataSequence *sequence = track->parent.sequence;
1564 MXFMetadataTimecodeComponent *component =
1565 MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1567 sequence->duration = mux->last_gc_position;
1568 component->parent.duration = mux->last_gc_position;
1572 guint64 body_partition = mux->partition.this_partition;
1573 guint32 body_sid = mux->partition.body_sid;
1574 guint64 footer_partition = mux->offset;
1578 MXFRandomIndexPackEntry entry;
1579 GList *index_entries = NULL, *l;
1580 guint index_byte_count = 0;
1584 for (i = 0; i < mux->index_table->len; i++) {
1585 MXFIndexTableSegment *segment =
1586 &g_array_index (mux->index_table, MXFIndexTableSegment, i);
1587 GstBuffer *segment_buffer = mxf_index_table_segment_to_buffer (segment);
1589 index_byte_count += gst_buffer_get_size (segment_buffer);
1590 index_entries = g_list_prepend (index_entries, segment_buffer);
1593 mux->partition.type = MXF_PARTITION_PACK_FOOTER;
1594 mux->partition.closed = TRUE;
1595 mux->partition.complete = TRUE;
1596 mux->partition.this_partition = mux->offset;
1597 mux->partition.prev_partition = body_partition;
1598 mux->partition.footer_partition = mux->offset;
1599 mux->partition.header_byte_count = 0;
1600 mux->partition.index_byte_count = index_byte_count;
1601 mux->partition.index_sid =
1602 mux->preface->content_storage->essence_container_data[0]->index_sid;
1603 mux->partition.body_offset = 0;
1604 mux->partition.body_sid = 0;
1606 gst_mxf_mux_write_header_metadata (mux);
1608 index_entries = g_list_reverse (index_entries);
1609 for (l = index_entries; l; l = l->next) {
1610 if ((ret = gst_mxf_mux_push (mux, l->data)) != GST_FLOW_OK) {
1611 GST_ERROR_OBJECT (mux, "Failed pushing index table segment");
1614 g_list_free (index_entries);
1616 rip = g_array_sized_new (FALSE, FALSE, sizeof (MXFRandomIndexPackEntry), 3);
1619 g_array_append_val (rip, entry);
1620 entry.offset = body_partition;
1621 entry.body_sid = body_sid;
1622 g_array_append_val (rip, entry);
1623 entry.offset = footer_partition;
1625 g_array_append_val (rip, entry);
1627 packet = mxf_random_index_pack_to_buffer (rip);
1628 if ((ret = gst_mxf_mux_push (mux, packet)) != GST_FLOW_OK) {
1629 GST_ERROR_OBJECT (mux, "Failed pushing random index pack");
1631 g_array_free (rip, TRUE);
1633 /* Rewrite header partition with updated values */
1634 gst_segment_init (&segment, GST_FORMAT_BYTES);
1635 if (gst_pad_push_event (GST_AGGREGATOR_SRC_PAD (mux),
1636 gst_event_new_segment (&segment))) {
1638 mux->partition.type = MXF_PARTITION_PACK_HEADER;
1639 mux->partition.closed = TRUE;
1640 mux->partition.complete = TRUE;
1641 mux->partition.this_partition = 0;
1642 mux->partition.prev_partition = 0;
1643 mux->partition.footer_partition = footer_partition;
1644 mux->partition.header_byte_count = 0;
1645 mux->partition.index_byte_count = 0;
1646 mux->partition.index_sid = 0;
1647 mux->partition.body_offset = 0;
1648 mux->partition.body_sid = 0;
1650 ret = gst_mxf_mux_write_header_metadata (mux);
1651 if (ret != GST_FLOW_OK) {
1652 GST_ERROR_OBJECT (mux, "Rewriting header partition failed");
1656 g_assert (mux->offset == body_partition);
1658 mux->partition.type = MXF_PARTITION_PACK_BODY;
1659 mux->partition.closed = TRUE;
1660 mux->partition.complete = TRUE;
1661 mux->partition.this_partition = mux->offset;
1662 mux->partition.prev_partition = 0;
1663 mux->partition.footer_partition = footer_partition;
1664 mux->partition.header_byte_count = 0;
1665 mux->partition.index_byte_count = 0;
1666 mux->partition.index_sid = 0;
1667 mux->partition.body_offset = 0;
1668 mux->partition.body_sid =
1669 mux->preface->content_storage->essence_container_data[0]->body_sid;
1671 buf = mxf_partition_pack_to_buffer (&mux->partition);
1672 ret = gst_mxf_mux_push (mux, buf);
1673 if (ret != GST_FLOW_OK) {
1674 GST_ERROR_OBJECT (mux, "Rewriting body partition failed");
1678 GST_WARNING_OBJECT (mux, "Can't rewrite header partition");
1686 _sort_mux_pads (gconstpointer a, gconstpointer b)
1688 const GstMXFMuxPad *pa = a, *pb = b;
1689 MXFMetadataTrackType ta =
1690 mxf_metadata_track_identifier_parse (&pa->writer->data_definition);
1691 MXFMetadataTrackType tb =
1692 mxf_metadata_track_identifier_parse (&pb->writer->data_definition);
1697 return pa->source_track->parent.track_number -
1698 pa->source_track->parent.track_number;
1703 gst_mxf_mux_stop (GstAggregator * aggregator)
1705 GstMXFMux *mux = GST_MXF_MUX (aggregator);
1707 gst_mxf_mux_reset (mux);
1712 static GstFlowReturn
1713 gst_mxf_mux_aggregate (GstAggregator * aggregator, gboolean timeout)
1715 GstMXFMux *mux = GST_MXF_MUX (aggregator);
1716 GstMXFMuxPad *best = NULL;
1719 gboolean eos = TRUE;
1722 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1723 ("Live mixing and got a timeout. This is not supported yet"));
1724 ret = GST_FLOW_ERROR;
1728 if (mux->state == GST_MXF_MUX_STATE_ERROR) {
1729 GST_ERROR_OBJECT (mux, "Had an error before -- returning");
1730 return GST_FLOW_ERROR;
1731 } else if (mux->state == GST_MXF_MUX_STATE_EOS) {
1732 GST_WARNING_OBJECT (mux, "EOS");
1733 return GST_FLOW_EOS;
1736 if (mux->state == GST_MXF_MUX_STATE_HEADER) {
1739 if (GST_ELEMENT_CAST (mux)->sinkpads == NULL) {
1740 GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1741 ("No input streams configured"));
1742 ret = GST_FLOW_ERROR;
1746 caps = gst_caps_new_empty_simple ("application/mxf");
1747 gst_aggregator_set_src_caps (GST_AGGREGATOR (mux), caps);
1748 gst_caps_unref (caps);
1750 if ((ret = gst_mxf_mux_create_metadata (mux)) != GST_FLOW_OK)
1753 if ((ret = gst_mxf_mux_init_partition_pack (mux)) != GST_FLOW_OK)
1756 if ((ret = gst_mxf_mux_write_header_metadata (mux)) != GST_FLOW_OK)
1759 /* Sort pads, we will always write in that order */
1760 GST_OBJECT_LOCK (mux);
1761 GST_ELEMENT_CAST (mux)->sinkpads =
1762 g_list_sort (GST_ELEMENT_CAST (mux)->sinkpads, _sort_mux_pads);
1763 GST_OBJECT_UNLOCK (mux);
1765 /* Write body partition */
1766 ret = gst_mxf_mux_write_body_partition (mux);
1767 if (ret != GST_FLOW_OK)
1769 mux->state = GST_MXF_MUX_STATE_DATA;
1772 g_return_val_if_fail (g_hash_table_size (mux->metadata) > 0, GST_FLOW_ERROR);
1775 GST_OBJECT_LOCK (mux);
1776 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1778 GstMXFMuxPad *pad = l->data;
1780 GstClockTime next_gc_timestamp =
1781 gst_util_uint64_scale ((mux->last_gc_position + 1) * GST_SECOND,
1782 mux->min_edit_rate.d, mux->min_edit_rate.n);
1784 pad_eos = gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad));
1788 buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
1790 if ((!pad_eos || pad->have_complete_edit_unit ||
1791 gst_adapter_available (pad->adapter) > 0 || buffer)
1792 && pad->last_timestamp < next_gc_timestamp) {
1794 gst_buffer_unref (buffer);
1795 best = gst_object_ref (pad);
1797 } else if (!eos && !l->next) {
1798 mux->last_gc_position++;
1799 mux->last_gc_timestamp = next_gc_timestamp;
1802 gst_buffer_unref (buffer);
1807 gst_buffer_unref (buffer);
1809 GST_OBJECT_UNLOCK (mux);
1810 } while (!eos && best == NULL);
1813 ret = gst_mxf_mux_handle_buffer (mux, best);
1814 gst_object_unref (best);
1815 if (ret != GST_FLOW_OK)
1818 GST_DEBUG_OBJECT (mux, "Handling EOS");
1821 gst_object_unref (best);
1823 gst_mxf_mux_handle_eos (mux);
1824 mux->state = GST_MXF_MUX_STATE_EOS;
1825 return GST_FLOW_EOS;
1827 g_assert_not_reached ();
1834 mux->state = GST_MXF_MUX_STATE_ERROR;