2 * Copyright (C) 2008-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-mxfdemux
23 * mxfdemux demuxes an MXF file into the different contained streams.
26 * <title>Example launch line</title>
28 * gst-launch -v filesrc location=/path/to/mxf ! mxfdemux ! audioconvert ! autoaudiosink
29 * ]| This pipeline demuxes an MXF file and outputs one of the contained raw audio streams.
34 * - Seeking support: Use IndexTableSegments
35 * - Handle timecode tracks correctly (where is this documented?)
36 * - Handle drop-frame field of timecode tracks
37 * - Handle Generic container system items
38 * - Implement correct support for clip-wrapped essence elements.
39 * - Post structural metadata and descriptive metadata trees as a message on the bus
40 * and send them downstream as event.
41 * - Multichannel audio needs channel layouts, define them (SMPTE S320M?).
42 * - Correctly handle the different rectangles and aspect-ratio for video
43 * - Add more support for non-standard MXF used by Avid (bug #561922).
44 * - Fix frame layout stuff, i.e. interlaced/progressive
45 * - In pull mode first find the first buffer for every pad before pushing
46 * to prevent jumpy playback in the beginning due to resynchronization.
48 * - Implement SMPTE D11 essence and the digital cinema/MXF specs
56 #include "mxfessence.h"
60 static GstStaticPadTemplate mxf_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
63 GST_STATIC_CAPS ("application/mxf")
66 static GstStaticPadTemplate mxf_src_template =
67 GST_STATIC_PAD_TEMPLATE ("track_%u",
72 GST_DEBUG_CATEGORY_STATIC (mxfdemux_debug);
73 #define GST_CAT_DEFAULT mxfdemux_debug
75 GType gst_mxf_demux_pad_get_type (void);
76 G_DEFINE_TYPE (GstMXFDemuxPad, gst_mxf_demux_pad, GST_TYPE_PAD);
79 gst_mxf_demux_pad_finalize (GObject * object)
81 GstMXFDemuxPad *pad = GST_MXF_DEMUX_PAD (object);
84 gst_tag_list_unref (pad->tags);
88 G_OBJECT_CLASS (gst_mxf_demux_pad_parent_class)->finalize (object);
92 gst_mxf_demux_pad_class_init (GstMXFDemuxPadClass * klass)
94 GObjectClass *gobject_class = (GObjectClass *) klass;
96 gobject_class->finalize = gst_mxf_demux_pad_finalize;
100 gst_mxf_demux_pad_init (GstMXFDemuxPad * pad)
113 static gboolean gst_mxf_demux_sink_event (GstPad * pad, GstObject * parent,
115 static gboolean gst_mxf_demux_src_event (GstPad * pad, GstObject * parent,
117 static gboolean gst_mxf_demux_src_query (GstPad * pad, GstObject * parent,
120 #define gst_mxf_demux_parent_class parent_class
121 G_DEFINE_TYPE (GstMXFDemux, gst_mxf_demux, GST_TYPE_ELEMENT);
124 gst_mxf_demux_remove_pad (GstMXFDemuxPad * pad, GstMXFDemux * demux)
126 gst_flow_combiner_remove_pad (demux->flowcombiner, GST_PAD_CAST (pad));
127 gst_element_remove_pad (GST_ELEMENT (demux), GST_PAD_CAST (pad));
131 gst_mxf_demux_remove_pads (GstMXFDemux * demux)
133 g_ptr_array_foreach (demux->src, (GFunc) gst_mxf_demux_remove_pad, demux);
134 g_ptr_array_foreach (demux->src, (GFunc) gst_object_unref, NULL);
135 g_ptr_array_set_size (demux->src, 0);
139 gst_mxf_demux_partition_free (GstMXFDemuxPartition * partition)
141 mxf_partition_pack_reset (&partition->partition);
142 mxf_primer_pack_reset (&partition->primer);
148 gst_mxf_demux_reset_mxf_state (GstMXFDemux * demux)
152 GST_DEBUG_OBJECT (demux, "Resetting MXF state");
154 g_list_foreach (demux->partitions, (GFunc) gst_mxf_demux_partition_free,
156 g_list_free (demux->partitions);
157 demux->partitions = NULL;
159 demux->current_partition = NULL;
161 for (i = 0; i < demux->essence_tracks->len; i++) {
162 GstMXFDemuxEssenceTrack *t =
163 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
166 g_array_free (t->offsets, TRUE);
168 g_free (t->mapping_data);
171 gst_tag_list_unref (t->tags);
174 gst_caps_unref (t->caps);
176 g_array_set_size (demux->essence_tracks, 0);
180 gst_mxf_demux_reset_linked_metadata (GstMXFDemux * demux)
184 for (i = 0; i < demux->src->len; i++) {
185 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
187 pad->material_track = NULL;
188 pad->material_package = NULL;
189 pad->current_component = NULL;
192 for (i = 0; i < demux->essence_tracks->len; i++) {
193 GstMXFDemuxEssenceTrack *track =
194 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
196 track->source_package = NULL;
197 track->source_track = NULL;
200 demux->current_package = NULL;
204 gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
206 GST_DEBUG_OBJECT (demux, "Resetting metadata");
208 g_rw_lock_writer_lock (&demux->metadata_lock);
210 demux->update_metadata = TRUE;
211 demux->metadata_resolved = FALSE;
213 gst_mxf_demux_reset_linked_metadata (demux);
215 demux->preface = NULL;
217 if (demux->metadata) {
218 g_hash_table_destroy (demux->metadata);
220 demux->metadata = mxf_metadata_hash_table_new ();
223 gst_tag_list_unref (demux->tags);
227 g_rw_lock_writer_unlock (&demux->metadata_lock);
231 gst_mxf_demux_reset (GstMXFDemux * demux)
233 GST_DEBUG_OBJECT (demux, "cleaning up MXF demuxer");
235 demux->flushing = FALSE;
237 demux->footer_partition_pack_offset = 0;
240 demux->pull_footer_metadata = TRUE;
244 memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
246 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
248 if (demux->close_seg_event) {
249 gst_event_unref (demux->close_seg_event);
250 demux->close_seg_event = NULL;
253 gst_adapter_clear (demux->adapter);
255 gst_mxf_demux_remove_pads (demux);
257 if (demux->random_index_pack) {
258 g_array_free (demux->random_index_pack, TRUE);
259 demux->random_index_pack = NULL;
262 if (demux->pending_index_table_segments) {
265 for (l = demux->pending_index_table_segments; l; l = l->next) {
266 MXFIndexTableSegment *s = l->data;
267 mxf_index_table_segment_reset (s);
270 g_list_free (demux->pending_index_table_segments);
271 demux->pending_index_table_segments = NULL;
274 gst_mxf_demux_reset_mxf_state (demux);
275 gst_mxf_demux_reset_metadata (demux);
277 demux->have_group_id = FALSE;
278 demux->group_id = G_MAXUINT;
282 gst_mxf_demux_pull_range (GstMXFDemux * demux, guint64 offset,
283 guint size, GstBuffer ** buffer)
287 ret = gst_pad_pull_range (demux->sinkpad, offset, size, buffer);
288 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
289 GST_WARNING_OBJECT (demux,
290 "failed when pulling %u bytes from offset %" G_GUINT64_FORMAT ": %s",
291 size, offset, gst_flow_get_name (ret));
296 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
297 GST_WARNING_OBJECT (demux,
298 "partial pull got %" G_GSIZE_FORMAT " when expecting %u from offset %"
299 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
300 gst_buffer_unref (*buffer);
310 gst_mxf_demux_push_src_event (GstMXFDemux * demux, GstEvent * event)
315 GST_DEBUG_OBJECT (demux, "Pushing '%s' event downstream",
316 GST_EVENT_TYPE_NAME (event));
318 for (i = 0; i < demux->src->len; i++) {
319 GstMXFDemuxPad *pad = GST_MXF_DEMUX_PAD (g_ptr_array_index (demux->src, i));
321 if (pad->eos && GST_EVENT_TYPE (event) == GST_EVENT_EOS)
324 ret |= gst_pad_push_event (GST_PAD_CAST (pad), gst_event_ref (event));
327 gst_event_unref (event);
332 static GstMXFDemuxPad *
333 gst_mxf_demux_get_earliest_pad (GstMXFDemux * demux)
336 GstClockTime earliest = GST_CLOCK_TIME_NONE;
337 GstMXFDemuxPad *pad = NULL;
339 for (i = 0; i < demux->src->len; i++) {
340 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
342 if (!p->eos && p->position < earliest) {
343 earliest = p->position;
352 gst_mxf_demux_partition_compare (GstMXFDemuxPartition * a,
353 GstMXFDemuxPartition * b)
355 return (a->partition.this_partition - b->partition.this_partition);
359 gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, const MXFUL * key,
362 MXFPartitionPack partition;
364 GstMXFDemuxPartition *p = NULL;
368 GST_DEBUG_OBJECT (demux,
369 "Handling partition pack of size %" G_GSIZE_FORMAT " at offset %"
370 G_GUINT64_FORMAT, gst_buffer_get_size (buffer), demux->offset);
372 for (l = demux->partitions; l; l = l->next) {
373 GstMXFDemuxPartition *tmp = l->data;
375 if (tmp->partition.this_partition + demux->run_in == demux->offset &&
376 tmp->partition.major_version == 0x0001) {
377 GST_DEBUG_OBJECT (demux, "Partition already parsed");
384 gst_buffer_map (buffer, &map, GST_MAP_READ);
385 ret = mxf_partition_pack_parse (key, &partition, map.data, map.size);
386 gst_buffer_unmap (buffer, &map);
388 GST_ERROR_OBJECT (demux, "Parsing partition pack failed");
389 return GST_FLOW_ERROR;
392 if (partition.this_partition != demux->offset + demux->run_in) {
393 GST_WARNING_OBJECT (demux, "Partition with incorrect offset");
394 partition.this_partition = demux->offset + demux->run_in;
397 if (partition.type == MXF_PARTITION_PACK_HEADER)
398 demux->footer_partition_pack_offset = partition.footer_partition;
400 for (l = demux->partitions; l; l = l->next) {
401 GstMXFDemuxPartition *tmp = l->data;
403 if (tmp->partition.this_partition + demux->run_in == demux->offset) {
410 mxf_partition_pack_reset (&p->partition);
411 memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
413 p = g_new0 (GstMXFDemuxPartition, 1);
414 memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
416 g_list_insert_sorted (demux->partitions, p,
417 (GCompareFunc) gst_mxf_demux_partition_compare);
420 for (l = demux->partitions; l; l = l->next) {
421 GstMXFDemuxPartition *a, *b;
429 b->partition.prev_partition = a->partition.this_partition;
433 demux->current_partition = p;
439 gst_mxf_demux_handle_primer_pack (GstMXFDemux * demux, const MXFUL * key,
445 GST_DEBUG_OBJECT (demux,
446 "Handling primer pack of size %" G_GSIZE_FORMAT " at offset %"
447 G_GUINT64_FORMAT, gst_buffer_get_size (buffer), demux->offset);
449 if (G_UNLIKELY (!demux->current_partition)) {
450 GST_ERROR_OBJECT (demux, "Primer pack before partition pack");
451 return GST_FLOW_ERROR;
454 if (G_UNLIKELY (demux->current_partition->primer.mappings)) {
455 GST_DEBUG_OBJECT (demux, "Primer pack already exists");
459 gst_buffer_map (buffer, &map, GST_MAP_READ);
460 ret = mxf_primer_pack_parse (key, &demux->current_partition->primer,
462 gst_buffer_unmap (buffer, &map);
464 GST_ERROR_OBJECT (demux, "Parsing primer pack failed");
465 return GST_FLOW_ERROR;
468 demux->current_partition->primer.offset = demux->offset;
474 gst_mxf_demux_resolve_references (GstMXFDemux * demux)
476 GstFlowReturn ret = GST_FLOW_OK;
478 MXFMetadataBase *m = NULL;
479 GstStructure *structure;
481 g_rw_lock_writer_lock (&demux->metadata_lock);
483 GST_DEBUG_OBJECT (demux, "Resolve metadata references");
484 demux->update_metadata = FALSE;
486 if (!demux->metadata) {
487 GST_ERROR_OBJECT (demux, "No metadata yet");
488 g_rw_lock_writer_unlock (&demux->metadata_lock);
489 return GST_FLOW_ERROR;
492 g_hash_table_iter_init (&iter, demux->metadata);
493 while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
494 m->resolved = MXF_METADATA_BASE_RESOLVE_STATE_NONE;
497 g_hash_table_iter_init (&iter, demux->metadata);
498 while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
501 resolved = mxf_metadata_base_resolve (m, demux->metadata);
503 /* Resolving can fail for anything but the preface, as the preface
504 * will resolve everything required */
505 if (!resolved && MXF_IS_METADATA_PREFACE (m)) {
506 ret = GST_FLOW_ERROR;
511 demux->metadata_resolved = TRUE;
514 mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
516 demux->tags = gst_tag_list_new_empty ();
518 gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_STRUCTURE,
521 gst_structure_free (structure);
523 g_rw_lock_writer_unlock (&demux->metadata_lock);
528 demux->metadata_resolved = FALSE;
529 g_rw_lock_writer_unlock (&demux->metadata_lock);
534 static MXFMetadataGenericPackage *
535 gst_mxf_demux_find_package (GstMXFDemux * demux, const MXFUMID * umid)
537 MXFMetadataGenericPackage *ret = NULL;
540 if (demux->preface->content_storage
541 && demux->preface->content_storage->packages) {
542 for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
543 MXFMetadataGenericPackage *p =
544 demux->preface->content_storage->packages[i];
549 if (mxf_umid_is_equal (&p->package_uid, umid)) {
559 static MXFMetadataGenericPackage *
560 gst_mxf_demux_choose_package (GstMXFDemux * demux)
562 MXFMetadataGenericPackage *ret = NULL;
565 if (demux->requested_package_string) {
566 MXFUMID umid = { {0,}
569 if (!mxf_umid_from_string (demux->requested_package_string, &umid)) {
570 GST_ERROR_OBJECT (demux, "Invalid requested package");
572 g_free (demux->requested_package_string);
573 demux->requested_package_string = NULL;
575 ret = gst_mxf_demux_find_package (demux, &umid);
578 if (!ret && !mxf_umid_is_zero (&demux->current_package_uid))
579 ret = gst_mxf_demux_find_package (demux, &demux->current_package_uid);
581 if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
582 || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
583 && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
586 GST_WARNING_OBJECT (demux,
587 "Current package is not a material package or top-level source package, choosing the first best");
588 else if (!mxf_umid_is_zero (&demux->current_package_uid))
589 GST_WARNING_OBJECT (demux,
590 "Current package not found, choosing the first best");
592 ret = demux->preface->primary_package;
593 if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
594 || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
595 && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
599 for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
600 if (demux->preface->content_storage->packages[i] &&
601 MXF_IS_METADATA_MATERIAL_PACKAGE (demux->preface->content_storage->
604 MXF_METADATA_GENERIC_PACKAGE (demux->preface->content_storage->
611 GST_ERROR_OBJECT (demux, "No material package");
616 if (mxf_umid_is_equal (&ret->package_uid, &demux->current_package_uid)) {
617 gchar current_package_string[96];
619 gst_mxf_demux_remove_pads (demux);
620 memcpy (&demux->current_package_uid, &ret->package_uid, 32);
622 mxf_umid_to_string (&ret->package_uid, current_package_string);
623 demux->current_package_string = g_strdup (current_package_string);
624 g_object_notify (G_OBJECT (demux), "package");
627 demux->tags = gst_tag_list_new_empty ();
628 gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_UMID,
629 demux->current_package_string, NULL);
631 demux->current_package = ret;
637 gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux)
641 g_return_val_if_fail (demux->preface->content_storage, GST_FLOW_ERROR);
642 g_return_val_if_fail (demux->preface->content_storage->essence_container_data,
645 for (i = 0; i < demux->preface->content_storage->n_essence_container_data;
647 MXFMetadataEssenceContainerData *edata;
648 MXFMetadataSourcePackage *package;
650 if (demux->preface->content_storage->essence_container_data[i] == NULL)
653 edata = demux->preface->content_storage->essence_container_data[i];
655 if (!edata->linked_package) {
656 GST_WARNING_OBJECT (demux, "Linked package not resolved");
660 package = edata->linked_package;
662 if (!package->parent.tracks) {
663 GST_WARNING_OBJECT (demux, "Linked package with no resolved tracks");
667 for (j = 0; j < package->parent.n_tracks; j++) {
668 MXFMetadataTimelineTrack *track;
669 GstMXFDemuxEssenceTrack *etrack = NULL;
670 GstCaps *caps = NULL;
671 gboolean new = FALSE;
673 if (!package->parent.tracks[j]
674 || !MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[j]))
677 track = MXF_METADATA_TIMELINE_TRACK (package->parent.tracks[j]);
678 if ((track->parent.type & 0xf0) != 0x30)
681 if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0) {
682 GST_WARNING_OBJECT (demux, "Invalid edit rate");
686 for (k = 0; k < demux->essence_tracks->len; k++) {
687 GstMXFDemuxEssenceTrack *tmp =
688 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
691 if (tmp->track_number == track->parent.track_number &&
692 tmp->body_sid == edata->body_sid) {
693 if (tmp->track_id != track->parent.track_id ||
694 !mxf_umid_is_equal (&tmp->source_package_uid,
695 &package->parent.package_uid)) {
696 GST_ERROR_OBJECT (demux, "There already exists a different track "
697 "with this track number and body sid but a different source "
698 "or source track id -- ignoring");
707 GstMXFDemuxEssenceTrack tmp;
709 memset (&tmp, 0, sizeof (tmp));
710 tmp.body_sid = edata->body_sid;
711 tmp.track_number = track->parent.track_number;
712 tmp.track_id = track->parent.track_id;
713 memcpy (&tmp.source_package_uid, &package->parent.package_uid, 32);
715 if (demux->current_partition->partition.body_sid == edata->body_sid &&
716 demux->current_partition->partition.body_offset == 0)
721 g_array_append_val (demux->essence_tracks, tmp);
723 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
724 demux->essence_tracks->len - 1);
728 etrack->source_package = NULL;
729 etrack->source_track = NULL;
731 if (!track->parent.sequence) {
732 GST_WARNING_OBJECT (demux, "Source track has no sequence");
736 if (track->parent.n_descriptor == 0) {
737 GST_WARNING_OBJECT (demux, "Source track has no descriptors");
741 if (track->parent.sequence->duration > etrack->duration)
742 etrack->duration = track->parent.sequence->duration;
744 g_free (etrack->mapping_data);
745 etrack->mapping_data = NULL;
746 etrack->handler = NULL;
747 etrack->handle_func = NULL;
749 gst_tag_list_unref (etrack->tags);
752 etrack->handler = mxf_essence_element_handler_find (track);
753 if (!etrack->handler) {
754 gchar essence_container[48];
755 gchar essence_compression[48];
758 GST_WARNING_OBJECT (demux,
759 "No essence element handler for track %u found", i);
761 mxf_ul_to_string (&track->parent.descriptor[0]->essence_container,
764 if (track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE) {
765 if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->parent.
767 mxf_ul_to_string (&MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR
768 (track->parent.descriptor[0])->picture_essence_coding,
769 essence_compression);
772 g_strdup_printf ("video/x-mxf-%s-%s", essence_container,
773 essence_compression);
774 } else if (track->parent.type == MXF_METADATA_TRACK_SOUND_ESSENCE) {
775 if (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track->parent.
777 mxf_ul_to_string (&MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR
778 (track->parent.descriptor[0])->sound_essence_compression,
779 essence_compression);
782 g_strdup_printf ("audio/x-mxf-%s-%s", essence_container,
783 essence_compression);
784 } else if (track->parent.type == MXF_METADATA_TRACK_DATA_ESSENCE) {
785 if (MXF_IS_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (track->parent.
787 mxf_ul_to_string (&MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR
788 (track->parent.descriptor[0])->data_essence_coding,
789 essence_compression);
792 g_strdup_printf ("application/x-mxf-%s-%s", essence_container,
793 essence_compression);
796 g_assert_not_reached ();
799 caps = gst_caps_new_empty_simple (name);
803 etrack->handler->create_caps (track, &etrack->tags,
804 &etrack->handle_func, &etrack->mapping_data);
807 GST_DEBUG_OBJECT (demux, "Created caps %" GST_PTR_FORMAT, caps);
810 GST_WARNING_OBJECT (demux, "No caps created, ignoring stream");
811 g_free (etrack->mapping_data);
812 etrack->mapping_data = NULL;
814 gst_tag_list_unref (etrack->tags);
817 GST_WARNING_OBJECT (demux, "Couldn't create updated caps for stream");
818 } else if (!etrack->caps || !gst_caps_is_equal (etrack->caps, caps)) {
820 gst_caps_unref (etrack->caps);
823 gst_caps_unref (caps);
827 if (etrack->handler != NULL) {
828 MXFEssenceWrapping track_wrapping;
830 track_wrapping = etrack->handler->get_track_wrapping (track);
831 if (track_wrapping == MXF_ESSENCE_WRAPPING_CLIP_WRAPPING) {
832 GST_ELEMENT_ERROR (demux, STREAM, NOT_IMPLEMENTED, (NULL),
833 ("Clip essence wrapping is not implemented yet."));
834 return GST_FLOW_ERROR;
835 } else if (track_wrapping == MXF_ESSENCE_WRAPPING_CUSTOM_WRAPPING) {
836 GST_ELEMENT_ERROR (demux, STREAM, NOT_IMPLEMENTED, (NULL),
837 ("Custom essence wrappings are not supported."));
838 return GST_FLOW_ERROR;
842 etrack->source_package = package;
843 etrack->source_track = track;
848 g_free (etrack->mapping_data);
850 gst_tag_list_unref (etrack->tags);
852 gst_caps_unref (etrack->caps);
854 g_array_remove_index (demux->essence_tracks,
855 demux->essence_tracks->len - 1);
860 if (demux->essence_tracks->len == 0) {
861 GST_ERROR_OBJECT (demux, "No valid essence tracks in this file");
862 return GST_FLOW_ERROR;
865 for (i = 0; i < demux->essence_tracks->len; i++) {
866 GstMXFDemuxEssenceTrack *etrack =
867 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
869 if (!etrack->source_package || !etrack->source_track || !etrack->caps) {
870 GST_ERROR_OBJECT (demux, "Failed to update essence track %u", i);
871 return GST_FLOW_ERROR;
880 gst_mxf_demux_update_tracks (GstMXFDemux * demux)
882 MXFMetadataGenericPackage *current_package = NULL;
885 guint component_index;
887 GList *pads = NULL, *l;
889 g_rw_lock_writer_lock (&demux->metadata_lock);
890 GST_DEBUG_OBJECT (demux, "Updating tracks");
892 if ((ret = gst_mxf_demux_update_essence_tracks (demux)) != GST_FLOW_OK) {
896 current_package = gst_mxf_demux_choose_package (demux);
898 if (!current_package) {
899 GST_ERROR_OBJECT (demux, "Unable to find current package");
900 ret = GST_FLOW_ERROR;
902 } else if (!current_package->tracks) {
903 GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks");
904 ret = GST_FLOW_ERROR;
906 } else if (!current_package->n_essence_tracks) {
907 GST_ERROR_OBJECT (demux, "Current package has no essence tracks");
908 ret = GST_FLOW_ERROR;
912 first_run = (demux->src->len == 0);
914 for (i = 0; i < current_package->n_tracks; i++) {
915 MXFMetadataTimelineTrack *track = NULL;
916 MXFMetadataSequence *sequence;
917 MXFMetadataSourceClip *component = NULL;
918 MXFMetadataSourcePackage *source_package = NULL;
919 MXFMetadataTimelineTrack *source_track = NULL;
920 GstMXFDemuxEssenceTrack *etrack = NULL;
921 GstMXFDemuxPad *pad = NULL;
924 GST_DEBUG_OBJECT (demux, "Handling track %u", i);
926 if (!current_package->tracks[i]) {
927 GST_WARNING_OBJECT (demux, "Unresolved track");
931 if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
932 GST_DEBUG_OBJECT (demux, "No timeline track");
936 track = MXF_METADATA_TIMELINE_TRACK (current_package->tracks[i]);
939 /* Find pad from track_id */
940 for (j = 0; j < demux->src->len; j++) {
941 GstMXFDemuxPad *tmp = g_ptr_array_index (demux->src, j);
943 if (tmp->track_id == track->parent.track_id) {
951 component_index = pad->current_component_index;
955 if (!track->parent.sequence) {
956 GST_WARNING_OBJECT (demux, "Track with no sequence");
960 ret = GST_FLOW_ERROR;
965 sequence = track->parent.sequence;
967 if (MXF_IS_METADATA_SOURCE_PACKAGE (current_package)) {
968 GST_DEBUG_OBJECT (demux, "Playing source package");
971 source_package = MXF_METADATA_SOURCE_PACKAGE (current_package);
972 source_track = track;
973 } else if (sequence->structural_components
975 MXF_IS_METADATA_SOURCE_CLIP (sequence->structural_components
976 [component_index])) {
977 GST_DEBUG_OBJECT (demux, "Playing material package");
980 MXF_METADATA_SOURCE_CLIP (sequence->structural_components
983 GST_WARNING_OBJECT (demux, "NULL conponent in non source package");
987 ret = GST_FLOW_ERROR;
992 if (component->source_package && component->source_package->top_level &&
993 MXF_METADATA_GENERIC_PACKAGE (component->source_package)->tracks) {
994 MXFMetadataGenericPackage *tmp_pkg =
995 MXF_METADATA_GENERIC_PACKAGE (component->source_package);
997 source_package = component->source_package;
999 for (k = 0; k < tmp_pkg->n_tracks; k++) {
1000 MXFMetadataTrack *tmp = tmp_pkg->tracks[k];
1002 if (tmp->track_id == component->source_track_id) {
1003 source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1010 if (track->parent.type && (track->parent.type & 0xf0) != 0x30) {
1011 GST_DEBUG_OBJECT (demux, "No essence track");
1015 ret = GST_FLOW_ERROR;
1020 if (!source_package || track->parent.type == MXF_METADATA_TRACK_UNKNOWN
1022 GST_WARNING_OBJECT (demux,
1023 "No source package or track type for track found");
1027 ret = GST_FLOW_ERROR;
1032 for (k = 0; k < demux->essence_tracks->len; k++) {
1033 GstMXFDemuxEssenceTrack *tmp =
1034 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, k);
1036 if (tmp->source_package == source_package &&
1037 tmp->source_track == source_track) {
1044 GST_WARNING_OBJECT (demux, "No essence track for this track found");
1048 ret = GST_FLOW_ERROR;
1053 if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0 ||
1054 source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1055 GST_WARNING_OBJECT (demux, "Track has an invalid edit rate");
1059 ret = GST_FLOW_ERROR;
1064 if (MXF_IS_METADATA_MATERIAL_PACKAGE (current_package) && !component) {
1065 GST_WARNING_OBJECT (demux,
1066 "Playing material package but found no component for track");
1070 ret = GST_FLOW_ERROR;
1075 if (!source_package->descriptor) {
1076 GST_WARNING_OBJECT (demux, "Source package has no descriptors");
1080 ret = GST_FLOW_ERROR;
1085 if (!source_track->parent.descriptor) {
1086 GST_WARNING_OBJECT (demux, "No descriptor found for track");
1090 ret = GST_FLOW_ERROR;
1095 if (!pad && first_run) {
1096 GstPadTemplate *templ;
1100 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
1102 pad_name = g_strdup_printf ("track_%u", track->parent.track_id);
1104 g_assert (templ != NULL);
1107 pad = (GstMXFDemuxPad *) g_object_new (GST_TYPE_MXF_DEMUX_PAD,
1108 "name", pad_name, "direction", GST_PAD_SRC, "template", templ, NULL);
1109 pad->need_segment = TRUE;
1114 pad->tags = gst_tag_list_copy (demux->tags);
1118 GST_WARNING_OBJECT (demux,
1119 "Not the first pad addition run, ignoring new track");
1124 pad->track_id = track->parent.track_id;
1126 pad->material_package = current_package;
1127 pad->material_track = track;
1129 /* If we just added the pad initialize for the current component */
1130 if (first_run && MXF_IS_METADATA_MATERIAL_PACKAGE (current_package)) {
1131 pad->current_component_index = 0;
1132 pad->current_component_start = source_track->origin;
1134 if (component->parent.duration >= -1)
1135 pad->current_component_duration = component->parent.duration;
1137 pad->current_component_duration = -1;
1139 if (track->edit_rate.n != source_track->edit_rate.n ||
1140 track->edit_rate.d != source_track->edit_rate.d) {
1141 pad->current_component_start +=
1142 gst_util_uint64_scale (component->start_position,
1143 source_track->edit_rate.n * track->edit_rate.d,
1144 source_track->edit_rate.d * track->edit_rate.n);
1146 if (pad->current_component_duration != -1)
1147 pad->current_component_duration =
1148 gst_util_uint64_scale (pad->current_component_duration,
1149 source_track->edit_rate.n * track->edit_rate.d,
1150 source_track->edit_rate.d * track->edit_rate.n);
1152 pad->current_component_start += component->start_position;
1154 pad->current_essence_track_position = pad->current_component_start;
1157 /* NULL iff playing a source package */
1158 pad->current_component = component;
1160 pad->current_essence_track = etrack;
1164 gst_tag_list_insert (pad->tags, etrack->tags, GST_TAG_MERGE_REPLACE);
1166 pad->tags = gst_tag_list_copy (etrack->tags);
1169 pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1170 if (pad_caps && !gst_caps_is_equal (pad_caps, etrack->caps)) {
1171 gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1172 } else if (!pad_caps) {
1176 gst_pad_set_event_function (GST_PAD_CAST (pad),
1177 GST_DEBUG_FUNCPTR (gst_mxf_demux_src_event));
1179 gst_pad_set_query_function (GST_PAD_CAST (pad),
1180 GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query));
1182 gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
1183 gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
1186 gst_pad_create_stream_id_printf (GST_PAD_CAST (pad),
1187 GST_ELEMENT_CAST (demux), "%03u", pad->track_id);
1190 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
1192 if (gst_event_parse_group_id (event, &demux->group_id))
1193 demux->have_group_id = TRUE;
1195 demux->have_group_id = FALSE;
1196 gst_event_unref (event);
1197 } else if (!demux->have_group_id) {
1198 demux->have_group_id = TRUE;
1199 demux->group_id = gst_util_group_id_next ();
1201 event = gst_event_new_stream_start (stream_id);
1202 if (demux->have_group_id)
1203 gst_event_set_group_id (event, demux->group_id);
1205 gst_pad_push_event (GST_PAD_CAST (pad), event);
1208 gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1210 pads = g_list_prepend (pads, gst_object_ref (pad));
1212 g_ptr_array_add (demux->src, pad);
1213 pad->discont = TRUE;
1216 gst_caps_unref (pad_caps);
1219 if (demux->src->len > 0) {
1220 for (i = 0; i < demux->src->len; i++) {
1221 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
1223 if (!pad->material_track || !pad->material_package) {
1224 GST_ERROR_OBJECT (demux, "Unable to update existing pad");
1225 ret = GST_FLOW_ERROR;
1230 GST_ERROR_OBJECT (demux, "Couldn't create any streams");
1231 ret = GST_FLOW_ERROR;
1235 g_rw_lock_writer_unlock (&demux->metadata_lock);
1237 for (l = pads; l; l = l->next) {
1238 gst_flow_combiner_add_pad (demux->flowcombiner, l->data);
1239 gst_element_add_pad (GST_ELEMENT_CAST (demux), l->data);
1244 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1249 g_rw_lock_writer_unlock (&demux->metadata_lock);
1253 static GstFlowReturn
1254 gst_mxf_demux_handle_metadata (GstMXFDemux * demux, const MXFUL * key,
1258 MXFMetadata *metadata = NULL, *old = NULL;
1260 GstFlowReturn ret = GST_FLOW_OK;
1262 type = GST_READ_UINT16_BE (key->u + 13);
1264 GST_DEBUG_OBJECT (demux,
1265 "Handling metadata of size %" G_GSIZE_FORMAT " at offset %"
1266 G_GUINT64_FORMAT " of type 0x%04x", gst_buffer_get_size (buffer),
1267 demux->offset, type);
1269 if (G_UNLIKELY (!demux->current_partition)) {
1270 GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1271 return GST_FLOW_ERROR;
1274 if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1275 GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1276 return GST_FLOW_ERROR;
1279 if (demux->current_partition->parsed_metadata) {
1280 GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1284 gst_buffer_map (buffer, &map, GST_MAP_READ);
1286 mxf_metadata_new (type, &demux->current_partition->primer, demux->offset,
1287 map.data, map.size);
1288 gst_buffer_unmap (buffer, &map);
1291 GST_WARNING_OBJECT (demux,
1292 "Unknown or unhandled metadata of type 0x%04x", type);
1297 g_hash_table_lookup (demux->metadata,
1298 &MXF_METADATA_BASE (metadata)->instance_uid);
1300 if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (metadata)) {
1301 #ifndef GST_DISABLE_GST_DEBUG
1305 GST_DEBUG_OBJECT (demux,
1306 "Metadata with instance uid %s already exists and has different type '%s',"
1308 mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str),
1309 g_type_name (G_TYPE_FROM_INSTANCE (old)),
1310 g_type_name (G_TYPE_FROM_INSTANCE (metadata)));
1311 g_object_unref (metadata);
1312 return GST_FLOW_ERROR;
1314 && MXF_METADATA_BASE (old)->offset >=
1315 MXF_METADATA_BASE (metadata)->offset) {
1316 #ifndef GST_DISABLE_GST_DEBUG
1320 GST_DEBUG_OBJECT (demux,
1321 "Metadata with instance uid %s already exists and is newer",
1322 mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str));
1323 g_object_unref (metadata);
1327 g_rw_lock_writer_lock (&demux->metadata_lock);
1328 demux->update_metadata = TRUE;
1330 if (MXF_IS_METADATA_PREFACE (metadata)) {
1331 demux->preface = MXF_METADATA_PREFACE (metadata);
1334 gst_mxf_demux_reset_linked_metadata (demux);
1336 g_hash_table_replace (demux->metadata,
1337 &MXF_METADATA_BASE (metadata)->instance_uid, metadata);
1338 g_rw_lock_writer_unlock (&demux->metadata_lock);
1343 static GstFlowReturn
1344 gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux,
1345 const MXFUL * key, GstBuffer * buffer)
1350 GstFlowReturn ret = GST_FLOW_OK;
1351 MXFDescriptiveMetadata *m = NULL, *old = NULL;
1353 scheme = GST_READ_UINT8 (key->u + 12);
1354 type = GST_READ_UINT24_BE (key->u + 13);
1356 GST_DEBUG_OBJECT (demux,
1357 "Handling descriptive metadata of size %" G_GSIZE_FORMAT " at offset %"
1358 G_GUINT64_FORMAT " with scheme 0x%02x and type 0x%06x",
1359 gst_buffer_get_size (buffer), demux->offset, scheme, type);
1361 if (G_UNLIKELY (!demux->current_partition)) {
1362 GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1363 return GST_FLOW_ERROR;
1366 if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1367 GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1368 return GST_FLOW_ERROR;
1371 if (demux->current_partition->parsed_metadata) {
1372 GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1376 gst_buffer_map (buffer, &map, GST_MAP_READ);
1377 m = mxf_descriptive_metadata_new (scheme, type,
1378 &demux->current_partition->primer, demux->offset, map.data, map.size);
1379 gst_buffer_unmap (buffer, &map);
1382 GST_WARNING_OBJECT (demux,
1383 "Unknown or unhandled descriptive metadata of scheme 0x%02x and type 0x%06x",
1389 g_hash_table_lookup (demux->metadata,
1390 &MXF_METADATA_BASE (m)->instance_uid);
1392 if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (m)) {
1393 #ifndef GST_DISABLE_GST_DEBUG
1397 GST_DEBUG_OBJECT (demux,
1398 "Metadata with instance uid %s already exists and has different type '%s',"
1400 mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str),
1401 g_type_name (G_TYPE_FROM_INSTANCE (old)),
1402 g_type_name (G_TYPE_FROM_INSTANCE (m)));
1404 return GST_FLOW_ERROR;
1406 && MXF_METADATA_BASE (old)->offset >= MXF_METADATA_BASE (m)->offset) {
1407 #ifndef GST_DISABLE_GST_DEBUG
1411 GST_DEBUG_OBJECT (demux,
1412 "Metadata with instance uid %s already exists and is newer",
1413 mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str));
1418 g_rw_lock_writer_lock (&demux->metadata_lock);
1420 demux->update_metadata = TRUE;
1421 gst_mxf_demux_reset_linked_metadata (demux);
1423 g_hash_table_replace (demux->metadata, &MXF_METADATA_BASE (m)->instance_uid,
1426 g_rw_lock_writer_unlock (&demux->metadata_lock);
1431 static GstFlowReturn
1432 gst_mxf_demux_handle_generic_container_system_item (GstMXFDemux * demux,
1433 const MXFUL * key, GstBuffer * buffer)
1435 GST_DEBUG_OBJECT (demux,
1436 "Handling generic container system item of size %" G_GSIZE_FORMAT
1437 " at offset %" G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1440 if (demux->current_partition->essence_container_offset == 0)
1441 demux->current_partition->essence_container_offset =
1442 demux->offset - demux->current_partition->partition.this_partition -
1445 /* TODO: parse this */
1449 static GstFlowReturn
1450 gst_mxf_demux_pad_set_component (GstMXFDemux * demux, GstMXFDemuxPad * pad,
1453 GstFlowReturn ret = GST_FLOW_OK;
1455 MXFMetadataSequence *sequence;
1457 MXFMetadataSourcePackage *source_package = NULL;
1458 MXFMetadataTimelineTrack *source_track = NULL;
1459 gboolean update = (pad->current_component_index != i);
1461 pad->current_component_index = i;
1463 sequence = pad->material_track->parent.sequence;
1465 if (pad->current_component_index >= sequence->n_structural_components) {
1466 GST_DEBUG_OBJECT (demux, "After last structural component");
1467 pad->current_component_index = sequence->n_structural_components - 1;
1471 GST_DEBUG_OBJECT (demux, "Switching to component %u",
1472 pad->current_component_index);
1474 pad->current_component =
1475 MXF_METADATA_SOURCE_CLIP (sequence->structural_components[pad->
1476 current_component_index]);
1477 if (pad->current_component == NULL) {
1478 GST_ERROR_OBJECT (demux, "No such structural component");
1479 return GST_FLOW_ERROR;
1482 if (!pad->current_component->source_package
1483 || !pad->current_component->source_package->top_level
1484 || !MXF_METADATA_GENERIC_PACKAGE (pad->current_component->
1485 source_package)->tracks) {
1486 GST_ERROR_OBJECT (demux, "Invalid component");
1487 return GST_FLOW_ERROR;
1490 source_package = pad->current_component->source_package;
1492 for (k = 0; k < source_package->parent.n_tracks; k++) {
1493 MXFMetadataTrack *tmp = source_package->parent.tracks[k];
1495 if (tmp->track_id == pad->current_component->source_track_id) {
1496 source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1501 if (!source_track) {
1502 GST_ERROR_OBJECT (demux, "No source track found");
1503 return GST_FLOW_ERROR;
1506 pad->current_essence_track = NULL;
1508 for (k = 0; k < demux->essence_tracks->len; k++) {
1509 GstMXFDemuxEssenceTrack *tmp =
1510 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, k);
1512 if (tmp->source_package == source_package &&
1513 tmp->source_track == source_track) {
1514 pad->current_essence_track = tmp;
1519 if (!pad->current_essence_track) {
1520 GST_ERROR_OBJECT (demux, "No corresponding essence track found");
1521 return GST_FLOW_ERROR;
1524 if (!source_package->descriptor) {
1525 GST_ERROR_OBJECT (demux, "Source package has no descriptors");
1526 return GST_FLOW_ERROR;
1529 if (!source_track->parent.descriptor) {
1530 GST_ERROR_OBJECT (demux, "No descriptor found for track");
1531 return GST_FLOW_ERROR;
1534 if (source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1535 GST_ERROR_OBJECT (demux, "Source track has invalid edit rate");
1536 return GST_FLOW_ERROR;
1539 pad->current_component_start = source_track->origin;
1540 if (pad->current_component->parent.duration >= -1)
1541 pad->current_component_duration = pad->current_component->parent.duration;
1543 pad->current_component_duration = -1;
1545 if (pad->material_track->edit_rate.n != source_track->edit_rate.n ||
1546 pad->material_track->edit_rate.d != source_track->edit_rate.d) {
1547 pad->current_component_start +=
1548 gst_util_uint64_scale (pad->current_component->start_position,
1549 source_track->edit_rate.n * pad->material_track->edit_rate.d,
1550 source_track->edit_rate.d * pad->material_track->edit_rate.n);
1552 if (pad->current_component_duration != -1)
1553 pad->current_component_duration =
1554 gst_util_uint64_scale (pad->current_component_duration,
1555 source_track->edit_rate.n * pad->material_track->edit_rate.d,
1556 source_track->edit_rate.d * pad->material_track->edit_rate.n);
1558 pad->current_component_start += pad->current_component->start_position;
1560 pad->current_essence_track_position = pad->current_component_start;
1563 pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1564 if (!gst_caps_is_equal (pad_caps, pad->current_essence_track->caps)) {
1565 gst_pad_set_caps (GST_PAD_CAST (pad), pad->current_essence_track->caps);
1567 gst_caps_unref (pad_caps);
1571 if (pad->current_essence_track->tags)
1572 gst_tag_list_insert (pad->tags, pad->current_essence_track->tags,
1573 GST_TAG_MERGE_REPLACE);
1575 if (pad->current_essence_track->tags)
1576 pad->tags = gst_tag_list_copy (pad->current_essence_track->tags);
1580 if (ret == GST_FLOW_EOS) {
1581 pad->current_essence_track_position += pad->current_component_duration;
1587 static GstFlowReturn
1588 gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
1589 const MXFUL * key, GstBuffer * buffer, gboolean peek)
1591 GstFlowReturn ret = GST_FLOW_OK;
1592 guint32 track_number;
1594 GstBuffer *inbuf = NULL;
1595 GstBuffer *outbuf = NULL;
1596 GstMXFDemuxEssenceTrack *etrack = NULL;
1597 gboolean keyframe = TRUE;
1599 GST_DEBUG_OBJECT (demux,
1600 "Handling generic container essence element of size %" G_GSIZE_FORMAT
1601 " at offset %" G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1604 GST_DEBUG_OBJECT (demux, " type = 0x%02x", key->u[12]);
1605 GST_DEBUG_OBJECT (demux, " essence element count = 0x%02x", key->u[13]);
1606 GST_DEBUG_OBJECT (demux, " essence element type = 0x%02x", key->u[14]);
1607 GST_DEBUG_OBJECT (demux, " essence element number = 0x%02x", key->u[15]);
1609 if (demux->current_partition->essence_container_offset == 0)
1610 demux->current_partition->essence_container_offset =
1611 demux->offset - demux->current_partition->partition.this_partition -
1614 if (!demux->current_package) {
1615 GST_ERROR_OBJECT (demux, "No package selected yet");
1616 return GST_FLOW_ERROR;
1619 if (demux->src->len == 0) {
1620 GST_ERROR_OBJECT (demux, "No streams created yet");
1621 return GST_FLOW_ERROR;
1624 if (demux->essence_tracks->len == 0) {
1625 GST_ERROR_OBJECT (demux, "No essence streams found in the metadata");
1626 return GST_FLOW_ERROR;
1629 track_number = GST_READ_UINT32_BE (&key->u[12]);
1631 for (i = 0; i < demux->essence_tracks->len; i++) {
1632 GstMXFDemuxEssenceTrack *tmp =
1633 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
1635 if (tmp->body_sid == demux->current_partition->partition.body_sid &&
1636 (tmp->track_number == track_number || tmp->track_number == 0)) {
1643 GST_WARNING_OBJECT (demux,
1644 "No essence track for this essence element found");
1648 if (etrack->position == -1) {
1649 GST_DEBUG_OBJECT (demux,
1650 "Unknown essence track position, looking into index");
1651 if (etrack->offsets) {
1652 for (i = 0; i < etrack->offsets->len; i++) {
1653 GstMXFDemuxIndex *idx =
1654 &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
1656 if (idx->offset != 0 && idx->offset == demux->offset - demux->run_in) {
1657 etrack->position = i;
1663 if (etrack->position == -1) {
1664 GST_WARNING_OBJECT (demux, "Essence track position not in index");
1669 if (etrack->offsets && etrack->offsets->len > etrack->position) {
1670 keyframe = g_array_index (etrack->offsets, GstMXFDemuxIndex,
1671 etrack->position).keyframe;
1674 /* Create subbuffer to be able to change metadata */
1676 gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0,
1677 gst_buffer_get_size (buffer));
1680 GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1682 if (etrack->handle_func) {
1683 /* Takes ownership of inbuf */
1685 etrack->handle_func (key, inbuf, etrack->caps,
1686 etrack->source_track, etrack->mapping_data, &outbuf);
1694 if (ret != GST_FLOW_OK) {
1695 GST_ERROR_OBJECT (demux, "Failed to handle essence element");
1697 gst_buffer_unref (outbuf);
1704 keyframe = !GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1706 if (!etrack->offsets)
1707 etrack->offsets = g_array_new (FALSE, TRUE, sizeof (GstMXFDemuxIndex));
1710 if (etrack->offsets->len > etrack->position) {
1711 GstMXFDemuxIndex *index =
1712 &g_array_index (etrack->offsets, GstMXFDemuxIndex, etrack->position);
1714 index->offset = demux->offset - demux->run_in;
1715 index->keyframe = keyframe;
1717 GstMXFDemuxIndex index;
1719 index.offset = demux->offset - demux->run_in;
1720 index.keyframe = keyframe;
1721 g_array_insert_val (etrack->offsets, etrack->position, index);
1729 GST_DEBUG_OBJECT (demux, "No output buffer created");
1736 for (i = 0; i < demux->src->len; i++) {
1737 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
1739 if (pad->current_essence_track != etrack)
1743 GST_DEBUG_OBJECT (demux, "Pad is already EOS");
1747 if (etrack->position != pad->current_essence_track_position) {
1748 GST_DEBUG_OBJECT (demux, "Not at current component's position");
1753 GstMXFDemuxPad *earliest = gst_mxf_demux_get_earliest_pad (demux);
1755 if (earliest && earliest != pad && earliest->position < pad->position &&
1756 pad->position - earliest->position > demux->max_drift) {
1757 GST_DEBUG_OBJECT (demux, "Pad is too far ahead of time");
1762 /* Create another subbuffer to have writable metadata */
1764 gst_buffer_copy_region (inbuf, GST_BUFFER_COPY_ALL, 0,
1765 gst_buffer_get_size (inbuf));
1767 GST_BUFFER_DTS (outbuf) = pad->position;
1768 GST_BUFFER_PTS (outbuf) = pad->position;
1769 GST_BUFFER_DURATION (outbuf) =
1770 gst_util_uint64_scale (GST_SECOND,
1771 pad->current_essence_track->source_track->edit_rate.d,
1772 pad->current_essence_track->source_track->edit_rate.n);
1773 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
1774 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
1776 /* Update accumulated error and compensate */
1779 (GST_SECOND * pad->current_essence_track->source_track->edit_rate.d) %
1780 pad->current_essence_track->source_track->edit_rate.n;
1781 pad->position_accumulated_error +=
1782 ((gdouble) abs_error) /
1783 ((gdouble) pad->current_essence_track->source_track->edit_rate.n);
1785 if (pad->position_accumulated_error >= 1.0) {
1786 GST_BUFFER_DURATION (outbuf) += 1;
1787 pad->position_accumulated_error -= 1.0;
1790 if (pad->need_segment) {
1793 if (demux->close_seg_event)
1794 gst_pad_push_event (GST_PAD_CAST (pad),
1795 gst_event_ref (demux->close_seg_event));
1797 e = gst_event_new_segment (&demux->segment);
1798 gst_event_set_seqnum (e, demux->seqnum);
1799 gst_pad_push_event (GST_PAD_CAST (pad), e);
1800 pad->need_segment = FALSE;
1804 gst_pad_push_event (GST_PAD_CAST (pad), gst_event_new_tag (pad->tags));
1808 pad->position += GST_BUFFER_DURATION (outbuf);
1810 GST_DEBUG_OBJECT (demux,
1811 "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u: timestamp %"
1812 GST_TIME_FORMAT " duration %" GST_TIME_FORMAT,
1813 gst_buffer_get_size (outbuf), pad->material_track->parent.track_id,
1814 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1815 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
1818 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1819 pad->discont = FALSE;
1822 ret = gst_pad_push (GST_PAD_CAST (pad), outbuf);
1824 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
1825 GST_LOG_OBJECT (demux, "combined return %s", gst_flow_get_name (ret));
1827 if (pad->position > demux->segment.position)
1828 demux->segment.position = pad->position;
1830 if (ret != GST_FLOW_OK)
1833 pad->current_essence_track_position++;
1835 if (pad->current_component) {
1836 if (pad->current_component_duration > 0 &&
1837 pad->current_essence_track_position - pad->current_component_start
1838 >= pad->current_component_duration) {
1839 GST_DEBUG_OBJECT (demux, "Switching to next component");
1842 gst_mxf_demux_pad_set_component (demux, pad,
1843 pad->current_component_index + 1);
1844 if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS) {
1845 GST_ERROR_OBJECT (demux, "Switching component failed");
1847 } else if (etrack->duration > 0
1848 && pad->current_essence_track_position >= etrack->duration) {
1849 GST_DEBUG_OBJECT (demux,
1850 "Current component position after end of essence track");
1853 } else if (etrack->duration > 0
1854 && pad->current_essence_track_position == etrack->duration) {
1855 GST_DEBUG_OBJECT (demux, "At the end of the essence track");
1859 if (ret == GST_FLOW_EOS) {
1862 GST_DEBUG_OBJECT (demux, "EOS for track");
1864 e = gst_event_new_eos ();
1865 gst_event_set_seqnum (e, demux->seqnum);
1866 gst_pad_push_event (GST_PAD_CAST (pad), e);
1870 if (ret != GST_FLOW_OK)
1876 gst_buffer_unref (inbuf);
1879 gst_buffer_unref (outbuf);
1886 static GstFlowReturn
1887 gst_mxf_demux_handle_random_index_pack (GstMXFDemux * demux, const MXFUL * key,
1895 GST_DEBUG_OBJECT (demux,
1896 "Handling random index pack of size %" G_GSIZE_FORMAT " at offset %"
1897 G_GUINT64_FORMAT, gst_buffer_get_size (buffer), demux->offset);
1899 if (demux->random_index_pack) {
1900 GST_DEBUG_OBJECT (demux, "Already parsed random index pack");
1904 gst_buffer_map (buffer, &map, GST_MAP_READ);
1906 mxf_random_index_pack_parse (key, map.data, map.size,
1907 &demux->random_index_pack);
1908 gst_buffer_unmap (buffer, &map);
1911 GST_ERROR_OBJECT (demux, "Parsing random index pack failed");
1912 return GST_FLOW_ERROR;
1915 for (i = 0; i < demux->random_index_pack->len; i++) {
1916 GstMXFDemuxPartition *p = NULL;
1917 MXFRandomIndexPackEntry *e =
1918 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry, i);
1920 if (e->offset < demux->run_in) {
1921 GST_ERROR_OBJECT (demux, "Invalid random index pack entry");
1922 return GST_FLOW_ERROR;
1925 for (l = demux->partitions; l; l = l->next) {
1926 GstMXFDemuxPartition *tmp = l->data;
1928 if (tmp->partition.this_partition + demux->run_in == e->offset) {
1935 p = g_new0 (GstMXFDemuxPartition, 1);
1936 p->partition.this_partition = e->offset - demux->run_in;
1937 p->partition.body_sid = e->body_sid;
1939 g_list_insert_sorted (demux->partitions, p,
1940 (GCompareFunc) gst_mxf_demux_partition_compare);
1944 for (l = demux->partitions; l; l = l->next) {
1945 GstMXFDemuxPartition *a, *b;
1947 if (l->next == NULL)
1953 b->partition.prev_partition = a->partition.this_partition;
1959 static GstFlowReturn
1960 gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux,
1961 const MXFUL * key, GstBuffer * buffer)
1963 MXFIndexTableSegment *segment;
1967 GST_DEBUG_OBJECT (demux,
1968 "Handling index table segment of size %" G_GSIZE_FORMAT " at offset %"
1969 G_GUINT64_FORMAT, gst_buffer_get_size (buffer), demux->offset);
1971 if (!demux->current_partition->primer.mappings) {
1972 GST_WARNING_OBJECT (demux, "Invalid primer pack");
1975 segment = g_new0 (MXFIndexTableSegment, 1);
1977 gst_buffer_map (buffer, &map, GST_MAP_READ);
1978 ret = mxf_index_table_segment_parse (key, segment,
1979 &demux->current_partition->primer, map.data, map.size);
1980 gst_buffer_unmap (buffer, &map);
1983 GST_ERROR_OBJECT (demux, "Parsing index table segment failed");
1984 return GST_FLOW_ERROR;
1987 demux->pending_index_table_segments =
1988 g_list_prepend (demux->pending_index_table_segments, segment);
1994 static GstFlowReturn
1995 gst_mxf_demux_pull_klv_packet (GstMXFDemux * demux, guint64 offset, MXFUL * key,
1996 GstBuffer ** outbuf, guint * read)
1998 GstBuffer *buffer = NULL;
2000 guint64 data_offset = 0;
2002 GstFlowReturn ret = GST_FLOW_OK;
2004 #ifndef GST_DISABLE_GST_DEBUG
2008 memset (key, 0, sizeof (MXFUL));
2010 /* Pull 16 byte key and first byte of BER encoded length */
2012 gst_mxf_demux_pull_range (demux, offset, 17, &buffer)) != GST_FLOW_OK)
2015 gst_buffer_map (buffer, &map, GST_MAP_READ);
2017 memcpy (key, map.data, 16);
2019 GST_DEBUG_OBJECT (demux, "Got KLV packet with key %s", mxf_ul_to_string (key,
2022 /* Decode BER encoded packet length */
2023 if ((map.data[16] & 0x80) == 0) {
2024 length = map.data[16];
2027 guint slen = map.data[16] & 0x7f;
2029 data_offset = 16 + 1 + slen;
2031 gst_buffer_unmap (buffer, &map);
2032 gst_buffer_unref (buffer);
2035 /* Must be at most 8 according to SMPTE-379M 5.3.4 */
2037 GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
2038 ret = GST_FLOW_ERROR;
2042 /* Now pull the length of the packet */
2043 if ((ret = gst_mxf_demux_pull_range (demux, offset + 17, slen,
2044 &buffer)) != GST_FLOW_OK)
2047 gst_buffer_map (buffer, &map, GST_MAP_READ);
2052 length = (length << 8) | *data;
2058 gst_buffer_unmap (buffer, &map);
2059 gst_buffer_unref (buffer);
2062 /* GStreamer's buffer sizes are stored in a guint so we
2063 * limit ourself to G_MAXUINT large buffers */
2064 if (length > G_MAXUINT) {
2065 GST_ERROR_OBJECT (demux,
2066 "Unsupported KLV packet length: %" G_GUINT64_FORMAT, length);
2067 ret = GST_FLOW_ERROR;
2071 GST_DEBUG_OBJECT (demux, "KLV packet with key %s has length "
2072 "%" G_GUINT64_FORMAT, mxf_ul_to_string (key, str), length);
2074 /* Pull the complete KLV packet */
2075 if ((ret = gst_mxf_demux_pull_range (demux, offset + data_offset, length,
2076 &buffer)) != GST_FLOW_OK)
2082 *read = data_offset + length;
2086 gst_buffer_unref (buffer);
2092 gst_mxf_demux_pull_random_index_pack (GstMXFDemux * demux)
2096 gint64 filesize = -1;
2097 GstFormat fmt = GST_FORMAT_BYTES;
2099 guint64 old_offset = demux->offset;
2103 if (!gst_pad_peer_query_duration (demux->sinkpad, fmt, &filesize) ||
2104 fmt != GST_FORMAT_BYTES || filesize == -1) {
2105 GST_DEBUG_OBJECT (demux, "Can't query upstream size");
2109 g_assert (filesize > 4);
2113 gst_mxf_demux_pull_range (demux, filesize - 4, 4,
2114 &buffer)) != GST_FLOW_OK) {
2115 GST_DEBUG_OBJECT (demux, "Failed pulling last 4 bytes");
2119 gst_buffer_map (buffer, &map, GST_MAP_READ);
2120 pack_size = GST_READ_UINT32_BE (map.data);
2121 gst_buffer_unmap (buffer, &map);
2123 gst_buffer_unref (buffer);
2125 if (pack_size < 20) {
2126 GST_DEBUG_OBJECT (demux, "Too small pack size (%u bytes)", pack_size);
2128 } else if (pack_size > filesize - 20) {
2129 GST_DEBUG_OBJECT (demux, "Too large pack size (%u bytes)", pack_size);
2135 gst_mxf_demux_pull_range (demux, filesize - pack_size, 16,
2136 &buffer)) != GST_FLOW_OK) {
2137 GST_DEBUG_OBJECT (demux, "Failed pulling random index pack key");
2141 gst_buffer_map (buffer, &map, GST_MAP_READ);
2142 memcpy (&key, map.data, 16);
2143 gst_buffer_unmap (buffer, &map);
2144 gst_buffer_unref (buffer);
2146 if (!mxf_is_random_index_pack (&key)) {
2147 GST_DEBUG_OBJECT (demux, "No random index pack");
2151 demux->offset = filesize - pack_size;
2153 gst_mxf_demux_pull_klv_packet (demux, filesize - pack_size, &key,
2154 &buffer, NULL)) != GST_FLOW_OK) {
2155 GST_DEBUG_OBJECT (demux, "Failed pulling random index pack");
2159 gst_mxf_demux_handle_random_index_pack (demux, &key, buffer);
2160 gst_buffer_unref (buffer);
2161 demux->offset = old_offset;
2165 gst_mxf_demux_parse_footer_metadata (GstMXFDemux * demux)
2167 guint64 old_offset = demux->offset;
2169 GstBuffer *buffer = NULL;
2171 GstFlowReturn ret = GST_FLOW_OK;
2172 GstMXFDemuxPartition *old_partition = demux->current_partition;
2174 demux->current_partition = NULL;
2176 gst_mxf_demux_reset_metadata (demux);
2178 if (demux->footer_partition_pack_offset != 0) {
2179 demux->offset = demux->run_in + demux->footer_partition_pack_offset;
2181 MXFRandomIndexPackEntry *entry =
2182 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry,
2183 demux->random_index_pack->len - 1);
2184 demux->offset = entry->offset;
2189 gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
2191 if (G_UNLIKELY (ret != GST_FLOW_OK))
2194 if (!mxf_is_partition_pack (&key))
2197 if (gst_mxf_demux_handle_partition_pack (demux, &key, buffer) != GST_FLOW_OK)
2200 demux->offset += read;
2201 gst_buffer_unref (buffer);
2204 if (demux->current_partition->partition.header_byte_count == 0) {
2205 if (demux->current_partition->partition.prev_partition == 0
2206 || demux->current_partition->partition.this_partition == 0)
2210 demux->run_in + demux->current_partition->partition.this_partition -
2211 demux->current_partition->partition.prev_partition;
2217 gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
2219 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2222 demux->current_partition->partition.this_partition -
2223 demux->current_partition->partition.prev_partition;
2227 if (mxf_is_fill (&key)) {
2228 demux->offset += read;
2229 gst_buffer_unref (buffer);
2231 } else if (mxf_is_primer_pack (&key)) {
2232 if (!demux->current_partition->primer.mappings) {
2233 if (gst_mxf_demux_handle_primer_pack (demux, &key,
2234 buffer) != GST_FLOW_OK) {
2235 demux->offset += read;
2236 gst_buffer_unref (buffer);
2240 demux->current_partition->partition.this_partition -
2241 demux->current_partition->partition.prev_partition;
2245 demux->offset += read;
2246 gst_buffer_unref (buffer);
2250 gst_buffer_unref (buffer);
2254 demux->current_partition->partition.this_partition -
2255 demux->current_partition->partition.prev_partition;
2260 /* parse metadata */
2261 while (demux->offset <
2262 demux->run_in + demux->current_partition->primer.offset +
2263 demux->current_partition->partition.header_byte_count) {
2265 gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
2267 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2270 demux->current_partition->partition.this_partition -
2271 demux->current_partition->partition.prev_partition;
2275 if (mxf_is_metadata (&key)) {
2276 ret = gst_mxf_demux_handle_metadata (demux, &key, buffer);
2277 demux->offset += read;
2278 gst_buffer_unref (buffer);
2281 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2282 gst_mxf_demux_reset_metadata (demux);
2285 demux->current_partition->partition.this_partition -
2286 demux->current_partition->partition.prev_partition;
2289 } else if (mxf_is_descriptive_metadata (&key)) {
2290 ret = gst_mxf_demux_handle_descriptive_metadata (demux, &key, buffer);
2291 demux->offset += read;
2292 gst_buffer_unref (buffer);
2294 } else if (mxf_is_fill (&key)) {
2295 demux->offset += read;
2296 gst_buffer_unref (buffer);
2298 } else if (mxf_is_generic_container_system_item (&key) ||
2299 mxf_is_generic_container_essence_element (&key) ||
2300 mxf_is_avid_essence_container_essence_element (&key)) {
2301 demux->offset += read;
2302 gst_buffer_unref (buffer);
2306 demux->offset += read;
2307 gst_buffer_unref (buffer);
2312 /* resolve references etc */
2314 if (gst_mxf_demux_resolve_references (demux) !=
2315 GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
2316 demux->current_partition->parsed_metadata = TRUE;
2318 demux->run_in + demux->current_partition->partition.this_partition -
2319 demux->current_partition->partition.prev_partition;
2325 gst_buffer_unref (buffer);
2327 demux->offset = old_offset;
2328 demux->current_partition = old_partition;
2331 static GstFlowReturn
2332 gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, const MXFUL * key,
2333 GstBuffer * buffer, gboolean peek)
2335 #ifndef GST_DISABLE_GST_DEBUG
2338 GstFlowReturn ret = GST_FLOW_OK;
2340 if (demux->update_metadata
2342 && (demux->offset >=
2343 demux->run_in + demux->current_partition->primer.offset +
2344 demux->current_partition->partition.header_byte_count ||
2345 mxf_is_generic_container_system_item (key) ||
2346 mxf_is_generic_container_essence_element (key) ||
2347 mxf_is_avid_essence_container_essence_element (key))) {
2348 demux->current_partition->parsed_metadata = TRUE;
2349 if ((ret = gst_mxf_demux_resolve_references (demux)) != GST_FLOW_OK ||
2350 (ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
2353 } else if (demux->metadata_resolved && demux->requested_package_string) {
2354 if ((ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
2359 if (!mxf_is_mxf_packet (key)) {
2360 GST_WARNING_OBJECT (demux,
2361 "Skipping non-MXF packet of size %" G_GSIZE_FORMAT " at offset %"
2362 G_GUINT64_FORMAT ", key: %s", gst_buffer_get_size (buffer),
2363 demux->offset, mxf_ul_to_string (key, key_str));
2364 } else if (mxf_is_partition_pack (key)) {
2365 ret = gst_mxf_demux_handle_partition_pack (demux, key, buffer);
2367 /* If this partition contains the start of an essence container
2368 * set the positions of all essence streams to 0
2370 if (ret == GST_FLOW_OK && demux->current_partition
2371 && demux->current_partition->partition.body_sid != 0
2372 && demux->current_partition->partition.body_offset == 0) {
2375 for (i = 0; i < demux->essence_tracks->len; i++) {
2376 GstMXFDemuxEssenceTrack *etrack =
2377 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
2379 if (etrack->body_sid != demux->current_partition->partition.body_sid)
2382 etrack->position = 0;
2385 } else if (mxf_is_primer_pack (key)) {
2386 ret = gst_mxf_demux_handle_primer_pack (demux, key, buffer);
2387 } else if (mxf_is_metadata (key)) {
2388 ret = gst_mxf_demux_handle_metadata (demux, key, buffer);
2389 } else if (mxf_is_descriptive_metadata (key)) {
2390 ret = gst_mxf_demux_handle_descriptive_metadata (demux, key, buffer);
2391 } else if (mxf_is_generic_container_system_item (key)) {
2393 gst_mxf_demux_handle_generic_container_system_item (demux, key, buffer);
2394 } else if (mxf_is_generic_container_essence_element (key) ||
2395 mxf_is_avid_essence_container_essence_element (key)) {
2397 gst_mxf_demux_handle_generic_container_essence_element (demux, key,
2399 } else if (mxf_is_random_index_pack (key)) {
2400 ret = gst_mxf_demux_handle_random_index_pack (demux, key, buffer);
2401 } else if (mxf_is_index_table_segment (key)) {
2402 ret = gst_mxf_demux_handle_index_table_segment (demux, key, buffer);
2403 } else if (mxf_is_fill (key)) {
2404 GST_DEBUG_OBJECT (demux,
2405 "Skipping filler packet of size %" G_GSIZE_FORMAT " at offset %"
2406 G_GUINT64_FORMAT, gst_buffer_get_size (buffer), demux->offset);
2408 GST_DEBUG_OBJECT (demux,
2409 "Skipping unknown packet of size %" G_GSIZE_FORMAT " at offset %"
2410 G_GUINT64_FORMAT ", key: %s", gst_buffer_get_size (buffer),
2411 demux->offset, mxf_ul_to_string (key, key_str));
2414 /* In pull mode try to get the last metadata */
2415 if (mxf_is_partition_pack (key) && ret == GST_FLOW_OK
2416 && demux->pull_footer_metadata
2417 && demux->random_access && demux->current_partition
2418 && demux->current_partition->partition.type == MXF_PARTITION_PACK_HEADER
2419 && (!demux->current_partition->partition.closed
2420 || !demux->current_partition->partition.complete)
2421 && (demux->footer_partition_pack_offset != 0 || demux->random_index_pack)) {
2422 GST_DEBUG_OBJECT (demux,
2423 "Open or incomplete header partition, trying to get final metadata from the last partitions");
2424 gst_mxf_demux_parse_footer_metadata (demux);
2425 demux->pull_footer_metadata = FALSE;
2427 if (demux->current_partition->partition.body_sid != 0 &&
2428 demux->current_partition->partition.body_offset == 0) {
2430 for (i = 0; i < demux->essence_tracks->len; i++) {
2431 GstMXFDemuxEssenceTrack *etrack =
2432 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
2434 if (etrack->body_sid != demux->current_partition->partition.body_sid)
2437 etrack->position = 0;
2447 gst_mxf_demux_set_partition_for_offset (GstMXFDemux * demux, guint64 offset)
2451 /* This partition will already be parsed, otherwise
2452 * the position wouldn't be in the index */
2453 for (l = demux->partitions; l; l = l->next) {
2454 GstMXFDemuxPartition *p = l->data;
2456 if (p->partition.this_partition + demux->run_in <= offset)
2457 demux->current_partition = p;
2462 gst_mxf_demux_find_essence_element (GstMXFDemux * demux,
2463 GstMXFDemuxEssenceTrack * etrack, gint64 * position, gboolean keyframe)
2465 GstFlowReturn ret = GST_FLOW_OK;
2466 guint64 old_offset = demux->offset;
2467 GstMXFDemuxPartition *old_partition = demux->current_partition;
2470 GST_DEBUG_OBJECT (demux, "Trying to find essence element %" G_GINT64_FORMAT
2471 " of track %u with body_sid %u (keyframe %d)", *position,
2472 etrack->track_number, etrack->body_sid, keyframe);
2476 if (etrack->duration > 0 && *position >= etrack->duration) {
2477 GST_WARNING_OBJECT (demux, "Position after end of essence track");
2481 /* First try to find an offset in our index */
2482 if (etrack->offsets && etrack->offsets->len > *position) {
2483 GstMXFDemuxIndex *idx =
2484 &g_array_index (etrack->offsets, GstMXFDemuxIndex, *position);
2485 guint64 current_offset = -1;
2486 gint64 current_position = *position;
2488 if (idx->offset != 0 && (!keyframe || idx->keyframe)) {
2489 current_offset = idx->offset;
2490 } else if (idx->offset != 0) {
2492 while (current_position >= 0) {
2494 &g_array_index (etrack->offsets, GstMXFDemuxIndex,
2496 if (idx->offset == 0) {
2498 } else if (!idx->keyframe) {
2502 current_offset = idx->offset;
2508 if (current_offset != -1) {
2509 GST_DEBUG_OBJECT (demux, "Found in index at offset %" G_GUINT64_FORMAT,
2511 *position = current_position;
2512 return current_offset;
2516 GST_DEBUG_OBJECT (demux, "Not found in index");
2517 if (!demux->random_access) {
2518 guint64 new_offset = -1;
2519 gint64 new_position = -1;
2521 if (etrack->offsets && etrack->offsets->len) {
2522 for (i = etrack->offsets->len - 1; i >= 0; i--) {
2523 GstMXFDemuxIndex *idx =
2524 &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
2526 if (idx->offset != 0 && i <= *position && (!keyframe || idx->keyframe)) {
2527 new_offset = idx->offset;
2534 if (new_offset != -1) {
2535 *position = new_position;
2538 } else if (demux->random_access) {
2539 demux->offset = demux->run_in;
2540 if (etrack->offsets && etrack->offsets->len) {
2541 for (i = etrack->offsets->len - 1; i >= 0; i--) {
2542 GstMXFDemuxIndex *idx =
2543 &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
2545 if (idx->offset != 0 && i <= *position) {
2546 demux->offset = idx->offset + demux->run_in;
2551 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
2553 for (i = 0; i < demux->essence_tracks->len; i++) {
2554 GstMXFDemuxEssenceTrack *t =
2555 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
2557 t->position = (demux->offset == demux->run_in) ? 0 : -1;
2560 /* Else peek at all essence elements and complete our
2561 * index until we find the requested element
2563 while (ret == GST_FLOW_OK) {
2564 GstBuffer *buffer = NULL;
2569 gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
2572 if (ret == GST_FLOW_EOS) {
2573 for (i = 0; i < demux->essence_tracks->len; i++) {
2574 GstMXFDemuxEssenceTrack *t =
2575 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
2578 if (t->position > 0)
2579 t->duration = t->position;
2581 /* For the searched track this is really our position */
2582 etrack->duration = etrack->position;
2584 for (i = 0; i < demux->src->len; i++) {
2585 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
2588 && p->current_essence_track_position >=
2589 p->current_essence_track->duration) {
2593 e = gst_event_new_eos ();
2594 gst_event_set_seqnum (e, demux->seqnum);
2595 gst_pad_push_event (GST_PAD_CAST (p), e);
2600 if (G_UNLIKELY (ret != GST_FLOW_OK) && etrack->position <= *position) {
2601 demux->offset = old_offset;
2602 demux->current_partition = old_partition;
2604 } else if (G_UNLIKELY (ret == GST_FLOW_OK)) {
2605 ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer, TRUE);
2606 gst_buffer_unref (buffer);
2609 /* If we found the position read it from the index again */
2610 if (((ret == GST_FLOW_OK && etrack->position == *position + 2) ||
2611 (ret == GST_FLOW_EOS && etrack->position == *position + 1))
2612 && etrack->offsets && etrack->offsets->len > *position
2613 && g_array_index (etrack->offsets, GstMXFDemuxIndex,
2614 *position).offset != 0) {
2615 GST_DEBUG_OBJECT (demux, "Found at offset %" G_GUINT64_FORMAT,
2617 demux->offset = old_offset;
2618 demux->current_partition = old_partition;
2621 demux->offset += read;
2623 demux->offset = old_offset;
2624 demux->current_partition = old_partition;
2626 GST_DEBUG_OBJECT (demux, "Not found in this file");
2632 static GstFlowReturn
2633 gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
2635 GstBuffer *buffer = NULL;
2637 GstFlowReturn ret = GST_FLOW_OK;
2640 if (demux->src->len > 0) {
2641 if (!gst_mxf_demux_get_earliest_pad (demux)) {
2643 GST_DEBUG_OBJECT (demux, "All tracks are EOS");
2649 gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
2652 if (ret == GST_FLOW_EOS && demux->src->len > 0) {
2654 GstMXFDemuxPad *p = NULL;
2656 for (i = 0; i < demux->essence_tracks->len; i++) {
2657 GstMXFDemuxEssenceTrack *t =
2658 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
2660 if (t->position > 0)
2661 t->duration = t->position;
2664 for (i = 0; i < demux->src->len; i++) {
2665 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
2668 && p->current_essence_track_position >=
2669 p->current_essence_track->duration) {
2673 e = gst_event_new_eos ();
2674 gst_event_set_seqnum (e, demux->seqnum);
2675 gst_pad_push_event (GST_PAD_CAST (p), e);
2679 while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
2683 position = p->current_essence_track_position;
2686 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
2691 GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
2693 e = gst_event_new_eos ();
2694 gst_event_set_seqnum (e, demux->seqnum);
2695 gst_pad_push_event (GST_PAD_CAST (p), e);
2699 demux->offset = offset + demux->run_in;
2700 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
2702 p->current_essence_track->position = position;
2709 if (G_UNLIKELY (ret != GST_FLOW_OK))
2712 ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer, FALSE);
2713 demux->offset += read;
2715 if (ret == GST_FLOW_OK && demux->src->len > 0
2716 && demux->essence_tracks->len > 0) {
2717 GstMXFDemuxPad *earliest = NULL;
2718 /* We allow time drifts of at most 500ms */
2719 while ((earliest = gst_mxf_demux_get_earliest_pad (demux)) &&
2720 demux->segment.position - earliest->position > demux->max_drift) {
2724 GST_WARNING_OBJECT (demux,
2725 "Found synchronization issue -- trying to solve");
2727 position = earliest->current_essence_track_position;
2729 /* FIXME: This can probably be improved by using the
2730 * offset of position-1 if it's in the same partition
2731 * or the start of the position otherwise.
2732 * This way we won't skip elements from the same essence
2733 * container as etrack->position
2736 gst_mxf_demux_find_essence_element (demux,
2737 earliest->current_essence_track, &position, FALSE);
2741 GST_WARNING_OBJECT (demux,
2742 "Failed to find offset for late essence track");
2743 earliest->eos = TRUE;
2744 e = gst_event_new_eos ();
2745 gst_event_set_seqnum (e, demux->seqnum);
2746 gst_pad_push_event (GST_PAD_CAST (earliest), e);
2750 demux->offset = offset + demux->run_in;
2751 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
2753 earliest->current_essence_track->position = position;
2760 gst_buffer_unref (buffer);
2766 gst_mxf_demux_loop (GstPad * pad)
2768 GstMXFDemux *demux = NULL;
2769 GstFlowReturn ret = GST_FLOW_OK;
2773 demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
2775 if (demux->run_in == -1) {
2776 /* Skip run-in, which is at most 64K and is finished
2777 * by a header partition pack */
2778 while (demux->offset < 64 * 1024) {
2779 GstBuffer *buffer = NULL;
2782 gst_mxf_demux_pull_range (demux, demux->offset, 16,
2783 &buffer)) != GST_FLOW_OK)
2786 gst_buffer_map (buffer, &map, GST_MAP_READ);
2787 res = mxf_is_header_partition_pack ((const MXFUL *) map.data);
2788 gst_buffer_unmap (buffer, &map);
2791 GST_DEBUG_OBJECT (demux,
2792 "Found header partition pack at offset %" G_GUINT64_FORMAT,
2794 demux->run_in = demux->offset;
2795 gst_buffer_unref (buffer);
2800 gst_buffer_unref (buffer);
2803 if (G_UNLIKELY (ret != GST_FLOW_OK))
2806 if (G_UNLIKELY (demux->run_in == -1)) {
2807 GST_ERROR_OBJECT (demux, "No valid header partition pack found");
2808 ret = GST_FLOW_ERROR;
2812 /* First of all pull&parse the random index pack at EOF */
2813 gst_mxf_demux_pull_random_index_pack (demux);
2816 /* Now actually do something */
2817 ret = gst_mxf_demux_pull_and_handle_klv_packet (demux);
2819 /* pause if something went wrong */
2820 if (G_UNLIKELY (ret != GST_FLOW_OK))
2823 /* check EOS condition */
2824 if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) &&
2825 (demux->segment.stop != -1) &&
2826 (demux->segment.position >= demux->segment.stop)) {
2828 gboolean eos = TRUE;
2830 for (i = 0; i < demux->src->len; i++) {
2831 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
2833 if (!p->eos && p->position < demux->segment.stop) {
2845 gst_object_unref (demux);
2851 const gchar *reason = gst_flow_get_name (ret);
2853 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2854 gst_pad_pause_task (pad);
2856 if (ret == GST_FLOW_EOS) {
2857 /* perform EOS logic */
2858 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2863 /* for segment playback we need to post when (in stream time)
2864 * we stopped, this is either stop (when set) or the duration. */
2865 if ((stop = demux->segment.stop) == -1)
2866 stop = demux->segment.duration;
2868 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2869 m = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2870 GST_FORMAT_TIME, stop);
2871 gst_message_set_seqnum (m, demux->seqnum);
2872 gst_element_post_message (GST_ELEMENT_CAST (demux), m);
2873 e = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
2874 gst_event_set_seqnum (e, demux->seqnum);
2875 gst_mxf_demux_push_src_event (demux, e);
2879 /* normal playback, send EOS to all linked pads */
2880 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2881 e = gst_event_new_eos ();
2882 gst_event_set_seqnum (e, demux->seqnum);
2883 if (!gst_mxf_demux_push_src_event (demux, e)) {
2884 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2887 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2890 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2891 ("Internal data stream error."),
2892 ("stream stopped, reason %s", reason));
2893 e = gst_event_new_eos ();
2894 gst_event_set_seqnum (e, demux->seqnum);
2895 gst_mxf_demux_push_src_event (demux, e);
2897 gst_object_unref (demux);
2902 static GstFlowReturn
2903 gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
2905 GstFlowReturn ret = GST_FLOW_OK;
2906 GstMXFDemux *demux = NULL;
2908 const guint8 *data = NULL;
2911 GstBuffer *buffer = NULL;
2913 #ifndef GST_DISABLE_GST_DEBUG
2917 demux = GST_MXF_DEMUX (parent);
2919 GST_LOG_OBJECT (demux,
2920 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
2921 G_GUINT64_FORMAT, gst_buffer_get_size (inbuf), GST_BUFFER_OFFSET (inbuf));
2923 if (demux->src->len > 0) {
2924 if (!gst_mxf_demux_get_earliest_pad (demux)) {
2926 GST_DEBUG_OBJECT (demux, "All tracks are EOS");
2931 if (G_UNLIKELY (GST_BUFFER_OFFSET (inbuf) == 0)) {
2932 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
2937 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (inbuf) != 0)) {
2938 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
2939 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2940 demux->offset = GST_BUFFER_OFFSET (inbuf);
2941 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
2942 } else if (demux->current_partition == NULL) {
2943 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
2946 gst_adapter_push (demux->adapter, inbuf);
2949 while (ret == GST_FLOW_OK) {
2950 if (G_UNLIKELY (demux->flushing)) {
2951 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
2952 ret = GST_FLOW_FLUSHING;
2956 if (gst_adapter_available (demux->adapter) < 16)
2959 if (demux->run_in == -1) {
2960 /* Skip run-in, which is at most 64K and is finished
2961 * by a header partition pack */
2963 while (demux->offset < 64 * 1024
2964 && gst_adapter_available (demux->adapter) >= 16) {
2965 data = gst_adapter_map (demux->adapter, 16);
2966 res = mxf_is_header_partition_pack ((const MXFUL *) data);
2967 gst_adapter_unmap (demux->adapter);
2970 GST_DEBUG_OBJECT (demux,
2971 "Found header partition pack at offset %" G_GUINT64_FORMAT,
2973 demux->run_in = demux->offset;
2976 gst_adapter_flush (demux->adapter, 1);
2979 } else if (demux->offset < demux->run_in) {
2980 guint64 flush = MIN (gst_adapter_available (demux->adapter),
2981 demux->run_in - demux->offset);
2982 gst_adapter_flush (demux->adapter, flush);
2983 demux->offset += flush;
2987 if (G_UNLIKELY (ret != GST_FLOW_OK))
2990 /* Need more data */
2991 if (demux->run_in == -1 && demux->offset < 64 * 1024)
2994 if (G_UNLIKELY (demux->run_in == -1)) {
2995 GST_ERROR_OBJECT (demux, "No valid header partition pack found");
2996 ret = GST_FLOW_ERROR;
3000 if (gst_adapter_available (demux->adapter) < 17)
3003 /* Now actually do something */
3004 memset (&key, 0, sizeof (MXFUL));
3006 /* Pull 16 byte key and first byte of BER encoded length */
3007 data = gst_adapter_map (demux->adapter, 17);
3009 memcpy (&key, data, 16);
3011 GST_DEBUG_OBJECT (demux, "Got KLV packet with key %s",
3012 mxf_ul_to_string (&key, str));
3014 /* Decode BER encoded packet length */
3015 if ((data[16] & 0x80) == 0) {
3019 guint slen = data[16] & 0x7f;
3021 offset = 16 + 1 + slen;
3023 gst_adapter_unmap (demux->adapter);
3025 /* Must be at most 8 according to SMPTE-379M 5.3.4 and
3026 * GStreamer buffers can only have a 4 bytes length */
3028 GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
3029 ret = GST_FLOW_ERROR;
3033 if (gst_adapter_available (demux->adapter) < 17 + slen)
3036 data = gst_adapter_map (demux->adapter, 17 + slen);
3041 length = (length << 8) | *data;
3047 gst_adapter_unmap (demux->adapter);
3049 /* GStreamer's buffer sizes are stored in a guint so we
3050 * limit ourself to G_MAXUINT large buffers */
3051 if (length > G_MAXUINT) {
3052 GST_ERROR_OBJECT (demux,
3053 "Unsupported KLV packet length: %" G_GUINT64_FORMAT, length);
3054 ret = GST_FLOW_ERROR;
3058 GST_DEBUG_OBJECT (demux, "KLV packet with key %s has length "
3059 "%" G_GUINT64_FORMAT, mxf_ul_to_string (&key, str), length);
3061 if (gst_adapter_available (demux->adapter) < offset + length)
3064 gst_adapter_flush (demux->adapter, offset);
3067 buffer = gst_adapter_take_buffer (demux->adapter, length);
3069 ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer, FALSE);
3070 gst_buffer_unref (buffer);
3073 demux->offset += offset + length;
3080 gst_mxf_demux_pad_set_position (GstMXFDemux * demux, GstMXFDemuxPad * p,
3084 GstClockTime sum = 0;
3085 MXFMetadataSourceClip *clip = NULL;
3087 if (!p->current_component) {
3088 p->current_essence_track_position =
3089 gst_util_uint64_scale (start, p->material_track->edit_rate.n,
3090 p->material_track->edit_rate.d * GST_SECOND);
3092 if (p->current_essence_track_position >= p->current_essence_track->duration
3093 && p->current_essence_track->duration > 0) {
3094 p->current_essence_track_position = p->current_essence_track->duration;
3096 gst_util_uint64_scale (p->current_essence_track->duration,
3097 p->material_track->edit_rate.d * GST_SECOND,
3098 p->material_track->edit_rate.n);
3100 p->position = start;
3102 p->position_accumulated_error = 0.0;
3107 for (i = 0; i < p->material_track->parent.sequence->n_structural_components;
3110 MXF_METADATA_SOURCE_CLIP (p->material_track->parent.sequence->
3111 structural_components[i]);
3113 if (clip->parent.duration <= 0)
3117 gst_util_uint64_scale (clip->parent.duration,
3118 p->material_track->edit_rate.d * GST_SECOND,
3119 p->material_track->edit_rate.n);
3125 if (i == p->material_track->parent.sequence->n_structural_components) {
3127 p->position_accumulated_error = 0.0;
3129 gst_mxf_demux_pad_set_component (demux, p, i);
3133 if (clip->parent.duration > 0)
3135 gst_util_uint64_scale (clip->parent.duration,
3136 p->material_track->edit_rate.d * GST_SECOND,
3137 p->material_track->edit_rate.n);
3141 gst_mxf_demux_pad_set_component (demux, p, i);
3144 gint64 essence_offset = gst_util_uint64_scale (start,
3145 p->current_essence_track->source_track->edit_rate.n,
3146 p->current_essence_track->source_track->edit_rate.d * GST_SECOND);
3148 p->current_essence_track_position += essence_offset;
3150 p->position = sum + gst_util_uint64_scale (essence_offset,
3151 GST_SECOND * p->material_track->edit_rate.d,
3152 p->material_track->edit_rate.n);
3153 p->position_accumulated_error = 0.0;
3156 if (p->current_essence_track_position >= p->current_essence_track->duration
3157 && p->current_essence_track->duration > 0) {
3158 p->current_essence_track_position = p->current_essence_track->duration;
3160 sum + gst_util_uint64_scale (p->current_component->parent.duration,
3161 p->material_track->edit_rate.d * GST_SECOND,
3162 p->material_track->edit_rate.n);
3167 gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event)
3171 GstSeekType start_type, stop_type;
3174 gboolean update, flush, keyframe;
3175 GstSegment seeksegment;
3179 gst_event_parse_seek (event, &rate, &format, &flags,
3180 &start_type, &start, &stop_type, &stop);
3181 seqnum = gst_event_get_seqnum (event);
3186 if (format != GST_FORMAT_TIME)
3189 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
3190 keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
3192 /* Work on a copy until we are sure the seek succeeded. */
3193 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
3195 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
3198 /* Apply the seek to our segment */
3199 gst_segment_do_seek (&seeksegment, rate, format, flags,
3200 start_type, start, stop_type, stop, &update);
3202 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
3205 if (flush || seeksegment.position != demux->segment.position) {
3207 guint64 new_offset = -1;
3210 if (!demux->metadata_resolved || demux->update_metadata) {
3211 if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
3212 gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
3213 goto unresolved_metadata;
3217 /* Do the actual seeking */
3218 for (i = 0; i < demux->src->len; i++) {
3219 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3223 /* Reset EOS flag on all pads */
3225 gst_mxf_demux_pad_set_position (demux, p, start);
3227 position = p->current_essence_track_position;
3228 off = gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
3229 &position, keyframe);
3230 new_offset = MIN (off, new_offset);
3234 if (new_offset == -1)
3237 new_offset += demux->run_in;
3239 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
3240 G_GUINT64_FORMAT, new_offset);
3241 e = gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
3242 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
3243 new_offset, GST_SEEK_TYPE_NONE, 0);
3244 gst_event_set_seqnum (e, seqnum);
3245 ret = gst_pad_push_event (demux->sinkpad, e);
3247 if (G_UNLIKELY (!ret)) {
3252 /* Tell all the stream a new segment is needed */
3253 for (i = 0; i < demux->src->len; i++) {
3254 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3255 p->need_segment = TRUE;
3258 for (i = 0; i < demux->essence_tracks->len; i++) {
3259 GstMXFDemuxEssenceTrack *t =
3260 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
3264 /* Ok seek succeeded, take the newly configured segment */
3265 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
3272 GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
3273 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
3277 GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
3280 unresolved_metadata:
3282 GST_WARNING_OBJECT (demux, "metadata can't be resolved");
3283 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
3287 GST_WARNING_OBJECT (demux, "upstream seek failed");
3288 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
3292 GST_WARNING_OBJECT (demux, "can't find new offset");
3293 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
3298 gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
3300 GstClockTime keyunit_ts;
3303 GstSeekType start_type, stop_type;
3306 gboolean update, flush, keyframe;
3307 GstSegment seeksegment;
3309 gboolean ret = TRUE;
3312 gst_event_parse_seek (event, &rate, &format, &flags,
3313 &start_type, &start, &stop_type, &stop);
3314 seqnum = gst_event_get_seqnum (event);
3316 if (format != GST_FORMAT_TIME)
3322 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
3323 keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
3330 /* Flush start up and downstream to make sure data flow and loops are
3332 e = gst_event_new_flush_start ();
3333 gst_event_set_seqnum (e, seqnum);
3334 gst_mxf_demux_push_src_event (demux, gst_event_ref (e));
3335 gst_pad_push_event (demux->sinkpad, e);
3337 /* Pause the pulling task */
3338 gst_pad_pause_task (demux->sinkpad);
3341 /* Take the stream lock */
3342 GST_PAD_STREAM_LOCK (demux->sinkpad);
3347 /* Stop flushing upstream we need to pull */
3348 e = gst_event_new_flush_stop (TRUE);
3349 gst_event_set_seqnum (e, seqnum);
3350 gst_pad_push_event (demux->sinkpad, e);
3353 /* Work on a copy until we are sure the seek succeeded. */
3354 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
3356 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
3359 /* Apply the seek to our segment */
3360 gst_segment_do_seek (&seeksegment, rate, format, flags,
3361 start_type, start, stop_type, stop, &update);
3363 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
3366 if (flush || seeksegment.position != demux->segment.position) {
3367 guint64 new_offset = -1;
3369 if (!demux->metadata_resolved || demux->update_metadata) {
3370 if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
3371 gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
3372 goto unresolved_metadata;
3376 /* Do the actual seeking */
3377 for (i = 0; i < demux->src->len; i++) {
3378 MXFMetadataTrackType track_type = MXF_METADATA_TRACK_UNKNOWN;
3379 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3383 if (p->material_track != NULL)
3384 track_type = p->material_track->parent.type;
3386 /* Reset EOS flag on all pads */
3388 gst_mxf_demux_pad_set_position (demux, p, start);
3390 /* we always want to send data starting with a key unit */
3391 position = p->current_essence_track_position;
3393 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
3396 GST_DEBUG_OBJECT (demux, "Unable to find offset for pad %s",
3398 p->current_essence_track_position = p->current_essence_track->duration;
3400 new_offset = MIN (off, new_offset);
3401 if (position != p->current_essence_track_position) {
3403 gst_util_uint64_scale (p->current_essence_track_position -
3405 GST_SECOND * p->current_essence_track->source_track->edit_rate.d,
3406 p->current_essence_track->source_track->edit_rate.n);
3408 p->current_essence_track_position = position;
3410 /* FIXME: what about DV + MPEG-TS container essence tracks? */
3411 if (track_type == MXF_METADATA_TRACK_PICTURE_ESSENCE) {
3412 keyunit_ts = MIN (p->position, keyunit_ts);
3417 if (new_offset == -1) {
3418 GST_WARNING_OBJECT (demux, "No new offset found");
3421 demux->offset = new_offset + demux->run_in;
3423 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
3426 if (G_UNLIKELY (demux->close_seg_event)) {
3427 gst_event_unref (demux->close_seg_event);
3428 demux->close_seg_event = NULL;
3434 /* Stop flushing, the sinks are at time 0 now */
3435 e = gst_event_new_flush_stop (TRUE);
3436 gst_event_set_seqnum (e, seqnum);
3437 gst_mxf_demux_push_src_event (demux, e);
3439 GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
3442 /* Close the current segment for a linear playback */
3443 demux->close_seg_event = gst_event_new_segment (&demux->segment);
3444 gst_event_set_seqnum (demux->close_seg_event, demux->seqnum);
3447 if (keyframe && keyunit_ts != start) {
3448 GST_INFO_OBJECT (demux, "key unit seek, adjusting segment start to "
3449 "%" GST_TIME_FORMAT, GST_TIME_ARGS (keyunit_ts));
3450 gst_segment_do_seek (&seeksegment, rate, format, flags,
3451 start_type, keyunit_ts, stop_type, stop, &update);
3454 /* Ok seek succeeded, take the newly configured segment */
3455 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
3457 /* Notify about the start of a new segment */
3458 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3461 m = gst_message_new_segment_start (GST_OBJECT (demux),
3462 demux->segment.format, demux->segment.position);
3463 gst_message_set_seqnum (m, seqnum);
3464 gst_element_post_message (GST_ELEMENT (demux), m);
3467 /* Tell all the stream a new segment is needed */
3468 for (i = 0; i < demux->src->len; i++) {
3469 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3470 p->need_segment = TRUE;
3473 for (i = 0; i < demux->essence_tracks->len; i++) {
3474 GstMXFDemuxEssenceTrack *t =
3475 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
3479 demux->seqnum = seqnum;
3481 gst_pad_start_task (demux->sinkpad,
3482 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
3484 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
3491 GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
3496 GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
3499 unresolved_metadata:
3501 gst_pad_start_task (demux->sinkpad,
3502 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
3503 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
3504 GST_WARNING_OBJECT (demux, "metadata can't be resolved");
3510 gst_mxf_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3512 GstMXFDemux *demux = GST_MXF_DEMUX (parent);
3515 GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
3517 switch (GST_EVENT_TYPE (event)) {
3518 case GST_EVENT_SEEK:
3519 if (demux->random_access)
3520 ret = gst_mxf_demux_seek_pull (demux, event);
3522 ret = gst_mxf_demux_seek_push (demux, event);
3523 gst_event_unref (event);
3526 ret = gst_pad_push_event (demux->sinkpad, event);
3534 gst_mxf_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
3536 GstMXFDemux *demux = GST_MXF_DEMUX (parent);
3537 gboolean ret = FALSE;
3538 GstMXFDemuxPad *mxfpad = GST_MXF_DEMUX_PAD (pad);
3540 GST_DEBUG_OBJECT (pad, "handling query %s",
3541 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3543 switch (GST_QUERY_TYPE (query)) {
3544 case GST_QUERY_POSITION:
3549 gst_query_parse_position (query, &format, NULL);
3550 if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
3553 pos = mxfpad->position;
3555 g_rw_lock_reader_lock (&demux->metadata_lock);
3556 if (format == GST_FORMAT_DEFAULT && pos != GST_CLOCK_TIME_NONE) {
3557 if (!mxfpad->material_track || mxfpad->material_track->edit_rate.n == 0
3558 || mxfpad->material_track->edit_rate.d == 0) {
3559 g_rw_lock_reader_unlock (&demux->metadata_lock);
3564 gst_util_uint64_scale (pos,
3565 mxfpad->material_track->edit_rate.n,
3566 mxfpad->material_track->edit_rate.d * GST_SECOND);
3568 g_rw_lock_reader_unlock (&demux->metadata_lock);
3570 GST_DEBUG_OBJECT (pad,
3571 "Returning position %" G_GINT64_FORMAT " in format %s", pos,
3572 gst_format_get_name (format));
3574 gst_query_set_position (query, format, pos);
3579 case GST_QUERY_DURATION:{
3583 gst_query_parse_duration (query, &format, NULL);
3584 if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
3587 g_rw_lock_reader_lock (&demux->metadata_lock);
3588 if (!mxfpad->material_track || !mxfpad->material_track->parent.sequence) {
3589 g_rw_lock_reader_unlock (&demux->metadata_lock);
3593 duration = mxfpad->material_track->parent.sequence->duration;
3597 if (duration != -1 && format == GST_FORMAT_TIME) {
3598 if (mxfpad->material_track->edit_rate.n == 0 ||
3599 mxfpad->material_track->edit_rate.d == 0) {
3600 g_rw_lock_reader_unlock (&demux->metadata_lock);
3605 gst_util_uint64_scale (duration,
3606 GST_SECOND * mxfpad->material_track->edit_rate.d,
3607 mxfpad->material_track->edit_rate.n);
3609 g_rw_lock_reader_unlock (&demux->metadata_lock);
3611 GST_DEBUG_OBJECT (pad,
3612 "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
3613 gst_format_get_name (format));
3615 gst_query_set_duration (query, format, duration);
3619 case GST_QUERY_SEEKING:{
3623 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3624 if (fmt != GST_FORMAT_TIME) {
3625 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3629 if (demux->random_access) {
3630 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
3632 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3635 seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3637 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3639 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
3641 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3646 case GST_QUERY_SEGMENT:{
3650 format = demux->segment.format;
3653 gst_segment_to_stream_time (&demux->segment, format,
3654 demux->segment.start);
3655 if ((stop = demux->segment.stop) == -1)
3656 stop = demux->segment.duration;
3658 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3660 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3665 ret = gst_pad_query_default (pad, parent, query);
3675 GST_DEBUG_OBJECT (pad, "query failed");
3681 gst_mxf_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
3684 GstPadMode mode = GST_PAD_MODE_PUSH;
3686 query = gst_query_new_scheduling ();
3688 if (gst_pad_peer_query (sinkpad, query)) {
3689 if (gst_query_has_scheduling_mode_with_flags (query,
3690 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE)) {
3691 GstSchedulingFlags flags;
3692 gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
3693 if (!(flags & GST_SCHEDULING_FLAG_SEQUENTIAL))
3694 mode = GST_PAD_MODE_PULL;
3697 gst_query_unref (query);
3699 return gst_pad_activate_mode (sinkpad, mode, TRUE);
3703 gst_mxf_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
3704 GstPadMode mode, gboolean active)
3708 demux = GST_MXF_DEMUX (parent);
3710 if (mode == GST_PAD_MODE_PUSH) {
3711 demux->random_access = FALSE;
3714 demux->random_access = TRUE;
3715 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_mxf_demux_loop,
3718 demux->random_access = FALSE;
3719 return gst_pad_stop_task (sinkpad);
3727 gst_mxf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3730 gboolean ret = FALSE;
3732 demux = GST_MXF_DEMUX (parent);
3734 GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
3736 switch (GST_EVENT_TYPE (event)) {
3737 case GST_EVENT_FLUSH_START:
3738 demux->flushing = TRUE;
3739 ret = gst_pad_event_default (pad, parent, event);
3741 case GST_EVENT_FLUSH_STOP:
3742 GST_DEBUG_OBJECT (demux, "flushing queued data in the MXF demuxer");
3744 gst_adapter_clear (demux->adapter);
3745 demux->flushing = FALSE;
3747 ret = gst_pad_event_default (pad, parent, event);
3749 case GST_EVENT_EOS:{
3750 GstMXFDemuxPad *p = NULL;
3753 for (i = 0; i < demux->essence_tracks->len; i++) {
3754 GstMXFDemuxEssenceTrack *t =
3755 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
3757 if (t->position > 0)
3758 t->duration = t->position;
3761 for (i = 0; i < demux->src->len; i++) {
3762 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3765 && p->current_essence_track_position >=
3766 p->current_essence_track->duration) {
3768 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
3772 while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
3776 position = p->current_essence_track_position;
3779 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
3782 GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
3784 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
3788 if (gst_pad_push_event (demux->sinkpad,
3789 gst_event_new_seek (demux->segment.rate, GST_FORMAT_BYTES,
3790 demux->segment.flags | GST_SEEK_FLAG_ACCURATE,
3791 GST_SEEK_TYPE_SET, offset + demux->run_in,
3792 GST_SEEK_TYPE_NONE, 0))) {
3794 for (i = 0; i < demux->essence_tracks->len; i++) {
3795 GstMXFDemuxEssenceTrack *etrack =
3796 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
3798 etrack->position = -1;
3803 GST_WARNING_OBJECT (demux,
3804 "Seek to remaining part of the file failed");
3808 /* and one more time for good measure apparently? */
3809 gst_pad_event_default (pad, parent, event);
3810 ret = (demux->src->len > 0);
3813 case GST_EVENT_SEGMENT:{
3816 for (i = 0; i < demux->essence_tracks->len; i++) {
3817 GstMXFDemuxEssenceTrack *t =
3818 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
3822 demux->current_partition = NULL;
3823 demux->seqnum = gst_event_get_seqnum (event);
3824 gst_event_unref (event);
3829 ret = gst_pad_event_default (pad, parent, event);
3839 gst_mxf_demux_query (GstElement * element, GstQuery * query)
3841 GstMXFDemux *demux = GST_MXF_DEMUX (element);
3842 gboolean ret = FALSE;
3844 GST_DEBUG_OBJECT (demux, "handling query %s",
3845 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3847 switch (GST_QUERY_TYPE (query)) {
3848 case GST_QUERY_POSITION:
3853 gst_query_parse_position (query, &format, NULL);
3854 if (format != GST_FORMAT_TIME)
3857 pos = demux->segment.position;
3859 GST_DEBUG_OBJECT (demux,
3860 "Returning position %" G_GINT64_FORMAT " in format %s", pos,
3861 gst_format_get_name (format));
3863 gst_query_set_position (query, format, pos);
3868 case GST_QUERY_DURATION:{
3869 gint64 duration = -1;
3873 gst_query_parse_duration (query, &format, NULL);
3874 if (format != GST_FORMAT_TIME)
3877 if (demux->src->len == 0)
3880 g_rw_lock_reader_lock (&demux->metadata_lock);
3881 for (i = 0; i < demux->src->len; i++) {
3882 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
3885 if (!pad->material_track || !pad->material_track->parent.sequence)
3888 pdur = pad->material_track->parent.sequence->duration;
3889 if (pad->material_track->edit_rate.n == 0 ||
3890 pad->material_track->edit_rate.d == 0 || pdur <= -1)
3894 gst_util_uint64_scale (pdur,
3895 GST_SECOND * pad->material_track->edit_rate.d,
3896 pad->material_track->edit_rate.n);
3897 duration = MAX (duration, pdur);
3899 g_rw_lock_reader_unlock (&demux->metadata_lock);
3901 if (duration == -1) {
3902 GST_DEBUG_OBJECT (demux, "No duration known (yet)");
3906 GST_DEBUG_OBJECT (demux,
3907 "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
3908 gst_format_get_name (format));
3910 gst_query_set_duration (query, format, duration);
3914 case GST_QUERY_SEEKING:{
3918 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3919 if (fmt != GST_FORMAT_TIME) {
3920 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3924 if (demux->random_access) {
3925 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
3927 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3930 seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3932 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3934 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
3936 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3941 case GST_QUERY_SEGMENT:{
3945 format = demux->segment.format;
3948 gst_segment_to_stream_time (&demux->segment, format,
3949 demux->segment.start);
3950 if ((stop = demux->segment.stop) == -1)
3951 stop = demux->segment.duration;
3953 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3955 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3960 /* else forward upstream */
3961 ret = gst_pad_peer_query (demux->sinkpad, query);
3971 GST_DEBUG_OBJECT (demux, "query failed");
3976 static GstStateChangeReturn
3977 gst_mxf_demux_change_state (GstElement * element, GstStateChange transition)
3979 GstMXFDemux *demux = GST_MXF_DEMUX (element);
3980 GstStateChangeReturn ret;
3982 switch (transition) {
3983 case GST_STATE_CHANGE_READY_TO_PAUSED:
3984 demux->seqnum = gst_util_seqnum_next ();
3990 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3991 if (ret == GST_STATE_CHANGE_FAILURE)
3994 switch (transition) {
3995 case GST_STATE_CHANGE_PAUSED_TO_READY:
3996 gst_mxf_demux_reset (demux);
4006 gst_mxf_demux_set_property (GObject * object, guint prop_id,
4007 const GValue * value, GParamSpec * pspec)
4009 GstMXFDemux *demux = GST_MXF_DEMUX (object);
4013 g_free (demux->requested_package_string);
4014 demux->requested_package_string = g_value_dup_string (value);
4016 case PROP_MAX_DRIFT:
4017 demux->max_drift = g_value_get_uint64 (value);
4020 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4026 gst_mxf_demux_get_property (GObject * object, guint prop_id,
4027 GValue * value, GParamSpec * pspec)
4029 GstMXFDemux *demux = GST_MXF_DEMUX (object);
4033 g_value_set_string (value, demux->current_package_string);
4035 case PROP_MAX_DRIFT:
4036 g_value_set_uint64 (value, demux->max_drift);
4038 case PROP_STRUCTURE:{
4041 g_rw_lock_reader_lock (&demux->metadata_lock);
4043 s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
4047 gst_value_set_structure (value, s);
4050 gst_structure_free (s);
4052 g_rw_lock_reader_unlock (&demux->metadata_lock);
4056 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4062 gst_mxf_demux_finalize (GObject * object)
4064 GstMXFDemux *demux = GST_MXF_DEMUX (object);
4066 gst_mxf_demux_reset (demux);
4068 if (demux->adapter) {
4069 g_object_unref (demux->adapter);
4070 demux->adapter = NULL;
4073 if (demux->flowcombiner) {
4074 gst_flow_combiner_free (demux->flowcombiner);
4075 demux->flowcombiner = NULL;
4078 if (demux->close_seg_event) {
4079 gst_event_unref (demux->close_seg_event);
4080 demux->close_seg_event = NULL;
4083 g_free (demux->current_package_string);
4084 demux->current_package_string = NULL;
4085 g_free (demux->requested_package_string);
4086 demux->requested_package_string = NULL;
4088 g_ptr_array_free (demux->src, TRUE);
4090 g_array_free (demux->essence_tracks, TRUE);
4091 demux->essence_tracks = NULL;
4093 g_hash_table_destroy (demux->metadata);
4095 g_rw_lock_clear (&demux->metadata_lock);
4097 G_OBJECT_CLASS (parent_class)->finalize (object);
4101 gst_mxf_demux_class_init (GstMXFDemuxClass * klass)
4103 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
4104 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
4106 GST_DEBUG_CATEGORY_INIT (mxfdemux_debug, "mxfdemux", 0, "MXF demuxer");
4108 parent_class = g_type_class_peek_parent (klass);
4110 gobject_class->finalize = gst_mxf_demux_finalize;
4111 gobject_class->set_property = gst_mxf_demux_set_property;
4112 gobject_class->get_property = gst_mxf_demux_get_property;
4114 g_object_class_install_property (gobject_class, PROP_PACKAGE,
4115 g_param_spec_string ("package", "Package",
4116 "Material or Source package to use for playback", NULL,
4117 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4119 g_object_class_install_property (gobject_class, PROP_MAX_DRIFT,
4120 g_param_spec_uint64 ("max-drift", "Maximum drift",
4121 "Maximum number of nanoseconds by which tracks can differ",
4122 100 * GST_MSECOND, G_MAXUINT64, 500 * GST_MSECOND,
4123 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4125 g_object_class_install_property (gobject_class, PROP_STRUCTURE,
4126 g_param_spec_boxed ("structure", "Structure",
4127 "Structural metadata of the MXF file",
4128 GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
4130 gstelement_class->change_state =
4131 GST_DEBUG_FUNCPTR (gst_mxf_demux_change_state);
4132 gstelement_class->query = GST_DEBUG_FUNCPTR (gst_mxf_demux_query);
4134 gst_element_class_add_pad_template (gstelement_class,
4135 gst_static_pad_template_get (&mxf_sink_template));
4136 gst_element_class_add_pad_template (gstelement_class,
4137 gst_static_pad_template_get (&mxf_src_template));
4138 gst_element_class_set_static_metadata (gstelement_class, "MXF Demuxer",
4140 "Demux MXF files", "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
4144 gst_mxf_demux_init (GstMXFDemux * demux)
4147 gst_pad_new_from_static_template (&mxf_sink_template, "sink");
4149 gst_pad_set_event_function (demux->sinkpad,
4150 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_event));
4151 gst_pad_set_chain_function (demux->sinkpad,
4152 GST_DEBUG_FUNCPTR (gst_mxf_demux_chain));
4153 gst_pad_set_activate_function (demux->sinkpad,
4154 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate));
4155 gst_pad_set_activatemode_function (demux->sinkpad,
4156 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_mode));
4158 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
4160 demux->max_drift = 500 * GST_MSECOND;
4162 demux->adapter = gst_adapter_new ();
4163 demux->flowcombiner = gst_flow_combiner_new ();
4164 g_rw_lock_init (&demux->metadata_lock);
4166 demux->src = g_ptr_array_new ();
4167 demux->essence_tracks =
4168 g_array_new (FALSE, FALSE, sizeof (GstMXFDemuxEssenceTrack));
4170 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4172 gst_mxf_demux_reset (demux);