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
24 * mxfdemux demuxes an MXF file into the different contained streams.
26 * ## Example launch line
28 * gst-launch-1.0 -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 * - Handle timecode tracks correctly (where is this documented?)
35 * - Handle drop-frame field of timecode tracks
36 * - Handle Generic container system items
37 * - Post structural metadata and descriptive metadata trees as a message on the bus
38 * and send them downstream as event.
39 * - Multichannel audio needs channel layouts, define them (SMPTE S320M?).
40 * - Correctly handle the different rectangles and aspect-ratio for video
41 * - Add more support for non-standard MXF used by Avid (bug #561922).
42 * - Fix frame layout stuff, i.e. interlaced/progressive
43 * - In pull mode first find the first buffer for every pad before pushing
44 * to prevent jumpy playback in the beginning due to resynchronization.
46 * - Implement SMPTE D11 essence and the digital cinema/MXF specs
53 #include "gstmxfelements.h"
55 #include "mxfessence.h"
59 static GstStaticPadTemplate mxf_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
62 GST_STATIC_CAPS ("application/mxf")
65 static GstStaticPadTemplate mxf_src_template =
66 GST_STATIC_PAD_TEMPLATE ("track_%u",
71 GST_DEBUG_CATEGORY_STATIC (mxfdemux_debug);
72 #define GST_CAT_DEFAULT mxfdemux_debug
74 /* Fill klv for the given offset, does not download the data */
76 gst_mxf_demux_peek_klv_packet (GstMXFDemux * demux, guint64 offset,
79 /* Ensures the klv data is present. Pulls it if needed */
81 gst_mxf_demux_fill_klv (GstMXFDemux * demux, GstMXFKLV * klv);
83 /* Call when done with a klv. Will release the buffer (if any) and will update
84 * the demuxer offset position */
85 static void gst_mxf_demux_consume_klv (GstMXFDemux * demux, GstMXFKLV * klv);
88 gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux, GstMXFKLV * klv);
90 static void collect_index_table_segments (GstMXFDemux * demux);
91 static gboolean find_entry_for_offset (GstMXFDemux * demux,
92 GstMXFDemuxEssenceTrack * etrack, guint64 offset,
93 GstMXFDemuxIndex * retentry);
95 GType gst_mxf_demux_pad_get_type (void);
96 G_DEFINE_TYPE (GstMXFDemuxPad, gst_mxf_demux_pad, GST_TYPE_PAD);
99 gst_mxf_demux_pad_finalize (GObject * object)
101 GstMXFDemuxPad *pad = GST_MXF_DEMUX_PAD (object);
104 gst_tag_list_unref (pad->tags);
108 G_OBJECT_CLASS (gst_mxf_demux_pad_parent_class)->finalize (object);
112 gst_mxf_demux_pad_class_init (GstMXFDemuxPadClass * klass)
114 GObjectClass *gobject_class = (GObjectClass *) klass;
116 gobject_class->finalize = gst_mxf_demux_pad_finalize;
120 gst_mxf_demux_pad_init (GstMXFDemuxPad * pad)
123 pad->current_material_track_position = 0;
126 #define DEFAULT_MAX_DRIFT 100 * GST_MSECOND
136 static gboolean gst_mxf_demux_sink_event (GstPad * pad, GstObject * parent,
138 static gboolean gst_mxf_demux_src_event (GstPad * pad, GstObject * parent,
140 static gboolean gst_mxf_demux_src_query (GstPad * pad, GstObject * parent,
143 #define gst_mxf_demux_parent_class parent_class
144 G_DEFINE_TYPE (GstMXFDemux, gst_mxf_demux, GST_TYPE_ELEMENT);
145 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (mxfdemux, "mxfdemux", GST_RANK_PRIMARY,
146 GST_TYPE_MXF_DEMUX, mxf_element_init (plugin));
149 gst_mxf_demux_remove_pad (GstMXFDemuxPad * pad, GstMXFDemux * demux)
151 gst_flow_combiner_remove_pad (demux->flowcombiner, GST_PAD_CAST (pad));
152 gst_element_remove_pad (GST_ELEMENT (demux), GST_PAD_CAST (pad));
156 gst_mxf_demux_remove_pads (GstMXFDemux * demux)
158 g_ptr_array_foreach (demux->src, (GFunc) gst_mxf_demux_remove_pad, demux);
159 g_ptr_array_foreach (demux->src, (GFunc) gst_object_unref, NULL);
160 g_ptr_array_set_size (demux->src, 0);
164 gst_mxf_demux_partition_free (GstMXFDemuxPartition * partition)
166 mxf_partition_pack_reset (&partition->partition);
167 mxf_primer_pack_reset (&partition->primer);
173 gst_mxf_demux_reset_mxf_state (GstMXFDemux * demux)
177 GST_DEBUG_OBJECT (demux, "Resetting MXF state");
179 g_list_foreach (demux->partitions, (GFunc) gst_mxf_demux_partition_free,
181 g_list_free (demux->partitions);
182 demux->partitions = NULL;
184 demux->current_partition = NULL;
186 for (i = 0; i < demux->essence_tracks->len; i++) {
187 GstMXFDemuxEssenceTrack *t =
188 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
191 g_array_free (t->offsets, TRUE);
193 g_free (t->mapping_data);
196 gst_tag_list_unref (t->tags);
199 gst_caps_unref (t->caps);
201 g_array_set_size (demux->essence_tracks, 0);
205 gst_mxf_demux_reset_linked_metadata (GstMXFDemux * demux)
209 for (i = 0; i < demux->src->len; i++) {
210 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
212 pad->material_track = NULL;
213 pad->material_package = NULL;
214 pad->current_component = NULL;
217 for (i = 0; i < demux->essence_tracks->len; i++) {
218 GstMXFDemuxEssenceTrack *track =
219 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
221 track->source_package = NULL;
222 track->delta_id = -1;
223 track->source_track = NULL;
226 demux->current_package = NULL;
230 gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
232 GST_DEBUG_OBJECT (demux, "Resetting metadata");
234 g_rw_lock_writer_lock (&demux->metadata_lock);
236 demux->update_metadata = TRUE;
237 demux->metadata_resolved = FALSE;
239 gst_mxf_demux_reset_linked_metadata (demux);
241 demux->preface = NULL;
243 if (demux->metadata) {
244 g_hash_table_destroy (demux->metadata);
246 demux->metadata = mxf_metadata_hash_table_new ();
249 gst_tag_list_unref (demux->tags);
253 g_rw_lock_writer_unlock (&demux->metadata_lock);
257 gst_mxf_demux_reset (GstMXFDemux * demux)
259 GST_DEBUG_OBJECT (demux, "cleaning up MXF demuxer");
261 demux->flushing = FALSE;
263 demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
265 demux->footer_partition_pack_offset = 0;
268 demux->pull_footer_metadata = TRUE;
272 memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
274 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
276 if (demux->close_seg_event) {
277 gst_event_unref (demux->close_seg_event);
278 demux->close_seg_event = NULL;
281 gst_adapter_clear (demux->adapter);
283 gst_mxf_demux_remove_pads (demux);
285 if (demux->random_index_pack) {
286 g_array_free (demux->random_index_pack, TRUE);
287 demux->random_index_pack = NULL;
290 if (demux->pending_index_table_segments) {
293 for (l = demux->pending_index_table_segments; l; l = l->next) {
294 MXFIndexTableSegment *s = l->data;
295 mxf_index_table_segment_reset (s);
298 g_list_free (demux->pending_index_table_segments);
299 demux->pending_index_table_segments = NULL;
302 if (demux->index_tables) {
305 for (l = demux->index_tables; l; l = l->next) {
306 GstMXFDemuxIndexTable *t = l->data;
307 g_array_free (t->segments, TRUE);
308 g_array_free (t->reverse_temporal_offsets, TRUE);
311 g_list_free (demux->index_tables);
312 demux->index_tables = NULL;
315 demux->index_table_segments_collected = FALSE;
317 gst_mxf_demux_reset_mxf_state (demux);
318 gst_mxf_demux_reset_metadata (demux);
320 demux->have_group_id = FALSE;
321 demux->group_id = G_MAXUINT;
325 gst_mxf_demux_pull_range (GstMXFDemux * demux, guint64 offset,
326 guint size, GstBuffer ** buffer)
330 ret = gst_pad_pull_range (demux->sinkpad, offset, size, buffer);
331 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
332 GST_WARNING_OBJECT (demux,
333 "failed when pulling %u bytes from offset %" G_GUINT64_FORMAT ": %s",
334 size, offset, gst_flow_get_name (ret));
339 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
340 GST_WARNING_OBJECT (demux,
341 "partial pull got %" G_GSIZE_FORMAT " when expecting %u from offset %"
342 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
343 gst_buffer_unref (*buffer);
353 gst_mxf_demux_push_src_event (GstMXFDemux * demux, GstEvent * event)
358 GST_DEBUG_OBJECT (demux, "Pushing '%s' event downstream",
359 GST_EVENT_TYPE_NAME (event));
361 for (i = 0; i < demux->src->len; i++) {
362 GstMXFDemuxPad *pad = GST_MXF_DEMUX_PAD (g_ptr_array_index (demux->src, i));
364 if (pad->eos && GST_EVENT_TYPE (event) == GST_EVENT_EOS)
367 ret |= gst_pad_push_event (GST_PAD_CAST (pad), gst_event_ref (event));
370 gst_event_unref (event);
375 static GstMXFDemuxPad *
376 gst_mxf_demux_get_earliest_pad (GstMXFDemux * demux)
379 GstClockTime earliest = GST_CLOCK_TIME_NONE;
380 GstMXFDemuxPad *pad = NULL;
382 for (i = 0; i < demux->src->len; i++) {
383 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
385 if (!p->eos && p->position < earliest) {
386 earliest = p->position;
395 gst_mxf_demux_partition_compare (GstMXFDemuxPartition * a,
396 GstMXFDemuxPartition * b)
398 if (a->partition.this_partition < b->partition.this_partition)
400 else if (a->partition.this_partition > b->partition.this_partition)
406 /* Final checks and variable calculation for tracks and partition. This function
407 * can be called repeatedly without any side-effect.
410 gst_mxf_demux_partition_postcheck (GstMXFDemux * demux,
411 GstMXFDemuxPartition * partition)
414 GstMXFDemuxPartition *old_partition = demux->current_partition;
416 /* If we already handled this partition or it doesn't contain any essence, skip */
417 if (partition->single_track || !partition->partition.body_sid)
420 for (i = 0; i < demux->essence_tracks->len; i++) {
421 GstMXFDemuxEssenceTrack *cand =
422 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
424 if (cand->body_sid != partition->partition.body_sid)
427 if (!cand->source_package->is_interleaved) {
428 GST_DEBUG_OBJECT (demux,
429 "Assigning single track %d (0x%08x) to partition at offset %"
430 G_GUINT64_FORMAT, cand->track_id, cand->track_number,
431 partition->partition.this_partition);
433 partition->single_track = cand;
435 if (partition->essence_container_offset != 0
436 && cand->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
437 GstMXFKLV essence_klv;
438 GstMXFDemuxIndex entry;
439 /* Update the essence container offset for the fact that the index
440 * stream offset is relative to the essence position and not to the
442 if (gst_mxf_demux_peek_klv_packet (demux,
443 partition->partition.this_partition +
444 partition->essence_container_offset,
445 &essence_klv) == GST_FLOW_OK) {
446 partition->essence_container_offset += essence_klv.data_offset;
447 /* And keep a copy of the clip/custom klv for this partition */
448 partition->clip_klv = essence_klv;
449 GST_DEBUG_OBJECT (demux,
450 "Non-frame wrapping, updated essence_container_offset to %"
451 G_GUINT64_FORMAT, partition->essence_container_offset);
453 /* And match it against index table, this will also update the track delta_id (if needed) */
454 demux->current_partition = partition;
455 find_entry_for_offset (demux, cand,
456 essence_klv.offset + essence_klv.data_offset, &entry);
457 demux->current_partition = old_partition;
467 gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, GstMXFKLV * klv)
469 MXFPartitionPack partition;
471 GstMXFDemuxPartition *p = NULL;
474 GstFlowReturn flowret;
476 GST_DEBUG_OBJECT (demux,
477 "Handling partition pack of size %" G_GSIZE_FORMAT " at offset %"
478 G_GUINT64_FORMAT, klv->length, klv->offset);
480 for (l = demux->partitions; l; l = l->next) {
481 GstMXFDemuxPartition *tmp = l->data;
483 if (tmp->partition.this_partition + demux->run_in == demux->offset &&
484 tmp->partition.major_version == 0x0001) {
485 GST_DEBUG_OBJECT (demux, "Partition already parsed");
491 flowret = gst_mxf_demux_fill_klv (demux, klv);
492 if (flowret != GST_FLOW_OK)
495 gst_buffer_map (klv->data, &map, GST_MAP_READ);
496 ret = mxf_partition_pack_parse (&klv->key, &partition, map.data, map.size);
497 gst_buffer_unmap (klv->data, &map);
499 GST_ERROR_OBJECT (demux, "Parsing partition pack failed");
500 return GST_FLOW_ERROR;
503 if (partition.this_partition != demux->offset + demux->run_in) {
504 GST_WARNING_OBJECT (demux,
505 "Partition with incorrect offset (this %" G_GUINT64_FORMAT
506 " demux offset %" G_GUINT64_FORMAT " run_in:%" G_GUINT64_FORMAT ")",
507 partition.this_partition, demux->offset, demux->run_in);
508 partition.this_partition = demux->offset + demux->run_in;
511 if (partition.type == MXF_PARTITION_PACK_HEADER)
512 demux->footer_partition_pack_offset = partition.footer_partition;
514 for (l = demux->partitions; l; l = l->next) {
515 GstMXFDemuxPartition *tmp = l->data;
517 if (tmp->partition.this_partition + demux->run_in == demux->offset) {
524 mxf_partition_pack_reset (&p->partition);
525 memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
527 p = g_new0 (GstMXFDemuxPartition, 1);
528 memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
530 g_list_insert_sorted (demux->partitions, p,
531 (GCompareFunc) gst_mxf_demux_partition_compare);
534 gst_mxf_demux_partition_postcheck (demux, p);
536 for (l = demux->partitions; l; l = l->next) {
537 GstMXFDemuxPartition *a, *b;
545 b->partition.prev_partition = a->partition.this_partition;
549 GST_DEBUG_OBJECT (demux,
550 "Current partition now %p (body_sid:%d index_sid:%d this_partition:%"
551 G_GUINT64_FORMAT ")", p, p->partition.body_sid, p->partition.index_sid,
552 p->partition.this_partition);
553 demux->current_partition = p;
559 gst_mxf_demux_handle_primer_pack (GstMXFDemux * demux, GstMXFKLV * klv)
563 GstFlowReturn flowret;
565 GST_DEBUG_OBJECT (demux,
566 "Handling primer pack of size %" G_GSIZE_FORMAT " at offset %"
567 G_GUINT64_FORMAT, klv->length, klv->offset);
569 if (G_UNLIKELY (!demux->current_partition)) {
570 GST_ERROR_OBJECT (demux, "Primer pack before partition pack");
571 return GST_FLOW_ERROR;
574 if (G_UNLIKELY (demux->current_partition->primer.mappings)) {
575 GST_DEBUG_OBJECT (demux, "Primer pack already exists");
579 flowret = gst_mxf_demux_fill_klv (demux, klv);
580 if (flowret != GST_FLOW_OK)
583 gst_buffer_map (klv->data, &map, GST_MAP_READ);
584 ret = mxf_primer_pack_parse (&klv->key, &demux->current_partition->primer,
586 gst_buffer_unmap (klv->data, &map);
588 GST_ERROR_OBJECT (demux, "Parsing primer pack failed");
589 return GST_FLOW_ERROR;
592 demux->current_partition->primer.offset = demux->offset;
598 gst_mxf_demux_resolve_references (GstMXFDemux * demux)
600 GstFlowReturn ret = GST_FLOW_OK;
602 MXFMetadataBase *m = NULL;
603 GstStructure *structure;
606 g_rw_lock_writer_lock (&demux->metadata_lock);
608 GST_DEBUG_OBJECT (demux, "Resolve metadata references");
609 demux->update_metadata = FALSE;
611 if (!demux->metadata) {
612 GST_ERROR_OBJECT (demux, "No metadata yet");
613 g_rw_lock_writer_unlock (&demux->metadata_lock);
614 return GST_FLOW_ERROR;
617 g_hash_table_iter_init (&iter, demux->metadata);
618 while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
619 m->resolved = MXF_METADATA_BASE_RESOLVE_STATE_NONE;
622 g_hash_table_iter_init (&iter, demux->metadata);
623 while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
626 resolved = mxf_metadata_base_resolve (m, demux->metadata);
628 /* Resolving can fail for anything but the preface, as the preface
629 * will resolve everything required */
630 if (!resolved && MXF_IS_METADATA_PREFACE (m)) {
631 ret = GST_FLOW_ERROR;
636 demux->metadata_resolved = TRUE;
639 mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
641 demux->tags = gst_tag_list_new_empty ();
643 gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_STRUCTURE,
646 gst_structure_free (structure);
648 /* Check for quirks */
649 for (i = 0; i < demux->preface->n_identifications; i++) {
650 MXFMetadataIdentification *identification =
651 demux->preface->identifications[i];
653 GST_DEBUG_OBJECT (demux, "product:'%s' company:'%s'",
654 identification->product_name, identification->company_name);
655 if (!g_strcmp0 (identification->product_name, "MXFTk Advanced") &&
656 !g_strcmp0 (identification->company_name, "OpenCube") &&
657 identification->product_version.major <= 2 &&
658 identification->product_version.minor <= 0) {
659 GST_WARNING_OBJECT (demux,
660 "Setting up quirk for misuse of temporal_order field");
661 demux->temporal_order_misuse = TRUE;
665 g_rw_lock_writer_unlock (&demux->metadata_lock);
670 demux->metadata_resolved = FALSE;
671 g_rw_lock_writer_unlock (&demux->metadata_lock);
676 static MXFMetadataGenericPackage *
677 gst_mxf_demux_find_package (GstMXFDemux * demux, const MXFUMID * umid)
679 MXFMetadataGenericPackage *ret = NULL;
682 if (demux->preface->content_storage
683 && demux->preface->content_storage->packages) {
684 for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
685 MXFMetadataGenericPackage *p =
686 demux->preface->content_storage->packages[i];
691 if (mxf_umid_is_equal (&p->package_uid, umid)) {
701 static MXFMetadataGenericPackage *
702 gst_mxf_demux_choose_package (GstMXFDemux * demux)
704 MXFMetadataGenericPackage *ret = NULL;
707 if (demux->requested_package_string) {
708 MXFUMID umid = { {0,}
711 if (!mxf_umid_from_string (demux->requested_package_string, &umid)) {
712 GST_ERROR_OBJECT (demux, "Invalid requested package");
714 g_free (demux->requested_package_string);
715 demux->requested_package_string = NULL;
717 ret = gst_mxf_demux_find_package (demux, &umid);
720 if (!ret && !mxf_umid_is_zero (&demux->current_package_uid))
721 ret = gst_mxf_demux_find_package (demux, &demux->current_package_uid);
723 if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
724 || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
725 && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
728 GST_WARNING_OBJECT (demux,
729 "Current package is not a material package or top-level source package, choosing the first best");
730 else if (!mxf_umid_is_zero (&demux->current_package_uid))
731 GST_WARNING_OBJECT (demux,
732 "Current package not found, choosing the first best");
734 ret = demux->preface->primary_package;
735 if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
736 || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
737 && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
741 for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
742 if (demux->preface->content_storage->packages[i] &&
743 MXF_IS_METADATA_MATERIAL_PACKAGE (demux->preface->content_storage->
746 MXF_METADATA_GENERIC_PACKAGE (demux->preface->content_storage->
753 GST_ERROR_OBJECT (demux, "No material package");
758 if (mxf_umid_is_equal (&ret->package_uid, &demux->current_package_uid)) {
759 gchar current_package_string[96];
761 gst_mxf_demux_remove_pads (demux);
762 memcpy (&demux->current_package_uid, &ret->package_uid, 32);
764 mxf_umid_to_string (&ret->package_uid, current_package_string);
765 demux->current_package_string = g_strdup (current_package_string);
766 g_object_notify (G_OBJECT (demux), "package");
769 demux->tags = gst_tag_list_new_empty ();
770 gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_UMID,
771 demux->current_package_string, NULL);
773 demux->current_package = ret;
779 gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux)
783 g_return_val_if_fail (demux->preface->content_storage, GST_FLOW_ERROR);
784 g_return_val_if_fail (demux->preface->content_storage->essence_container_data,
787 for (i = 0; i < demux->preface->content_storage->n_essence_container_data;
789 MXFMetadataEssenceContainerData *edata;
790 MXFMetadataSourcePackage *package;
791 MXFFraction common_rate = { 0, 0 };
793 if (demux->preface->content_storage->essence_container_data[i] == NULL)
796 edata = demux->preface->content_storage->essence_container_data[i];
798 if (!edata->linked_package) {
799 GST_WARNING_OBJECT (demux, "Linked package not resolved");
803 package = edata->linked_package;
805 if (!package->parent.tracks) {
806 GST_WARNING_OBJECT (demux, "Linked package with no resolved tracks");
810 for (j = 0; j < package->parent.n_tracks; j++) {
811 MXFMetadataTimelineTrack *track;
812 GstMXFDemuxEssenceTrack *etrack = NULL;
813 GstCaps *caps = NULL;
814 gboolean new = FALSE;
816 if (!package->parent.tracks[j]
817 || !MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[j])) {
818 GST_DEBUG_OBJECT (demux,
819 "Skipping non-timeline track (id:%d number:0x%08x)",
820 package->parent.tracks[j]->track_id,
821 package->parent.tracks[j]->track_number);
825 track = MXF_METADATA_TIMELINE_TRACK (package->parent.tracks[j]);
826 if ((track->parent.type & 0xf0) != 0x30) {
827 GST_DEBUG_OBJECT (demux,
828 "Skipping track of type 0x%02x (id:%d number:0x%08x)",
829 track->parent.type, track->parent.track_id,
830 track->parent.track_number);
834 if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0) {
835 GST_WARNING_OBJECT (demux, "Invalid edit rate");
839 if (package->is_interleaved) {
841 * S377-1:2019 "9.4.2 The MXF timing model"
843 * The value of Edit Rate shall be identical for every timeline Essence
844 * Track of the Top-Level File Package.
846 * The value of Edit Rate of the timeline Essence Tracks of one
847 * Top-Level File Package need not match the Edit Rate of the Essence
848 * Tracks of the other Top-Level File Packages.
850 * S377-1:2019 "9.5.5 Top-Level File Packages"
852 *12. All Essence Tracks of a Top-Level File Package **shall** have the
853 * same value of Edit Rate. All other Tracks of a Top-Level File
854 * Package **should** have the same value of Edit Rate as the
857 if (common_rate.n == 0 && common_rate.d == 0) {
858 common_rate = track->edit_rate;
859 } else if (common_rate.n * track->edit_rate.d !=
860 common_rate.d * track->edit_rate.n) {
861 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
862 ("Interleaved File Package doesn't have identical edit rate on all tracks."));
863 return GST_FLOW_ERROR;
867 for (k = 0; k < demux->essence_tracks->len; k++) {
868 GstMXFDemuxEssenceTrack *tmp =
869 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
872 if (tmp->track_number == track->parent.track_number &&
873 tmp->body_sid == edata->body_sid) {
874 if (tmp->track_id != track->parent.track_id ||
875 !mxf_umid_is_equal (&tmp->source_package_uid,
876 &package->parent.package_uid)) {
877 GST_ERROR_OBJECT (demux, "There already exists a different track "
878 "with this track number and body sid but a different source "
879 "or source track id -- ignoring");
888 GstMXFDemuxEssenceTrack tmp;
890 memset (&tmp, 0, sizeof (tmp));
891 tmp.body_sid = edata->body_sid;
892 tmp.index_sid = edata->index_sid;
893 tmp.track_number = track->parent.track_number;
894 tmp.track_id = track->parent.track_id;
895 memcpy (&tmp.source_package_uid, &package->parent.package_uid, 32);
897 if (demux->current_partition->partition.body_sid == edata->body_sid &&
898 demux->current_partition->partition.body_offset == 0)
903 g_array_append_val (demux->essence_tracks, tmp);
905 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
906 demux->essence_tracks->len - 1);
910 etrack->source_package = NULL;
911 etrack->source_track = NULL;
912 etrack->delta_id = -1;
914 if (!track->parent.sequence) {
915 GST_WARNING_OBJECT (demux, "Source track has no sequence");
919 if (track->parent.n_descriptor == 0) {
920 GST_WARNING_OBJECT (demux, "Source track has no descriptors");
924 if (track->parent.sequence->duration > etrack->duration)
925 etrack->duration = track->parent.sequence->duration;
927 g_free (etrack->mapping_data);
928 etrack->mapping_data = NULL;
929 etrack->handler = NULL;
930 etrack->handle_func = NULL;
932 gst_tag_list_unref (etrack->tags);
935 etrack->handler = mxf_essence_element_handler_find (track);
936 if (!etrack->handler) {
937 gchar essence_container[48];
938 gchar essence_compression[48];
941 GST_WARNING_OBJECT (demux,
942 "No essence element handler for track %u found", i);
944 mxf_ul_to_string (&track->parent.descriptor[0]->essence_container,
947 if (track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE) {
948 if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->parent.
950 mxf_ul_to_string (&MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR
951 (track->parent.descriptor[0])->picture_essence_coding,
952 essence_compression);
955 g_strdup_printf ("video/x-mxf-%s-%s", essence_container,
956 essence_compression);
957 } else if (track->parent.type == MXF_METADATA_TRACK_SOUND_ESSENCE) {
958 if (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track->parent.
960 mxf_ul_to_string (&MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR
961 (track->parent.descriptor[0])->sound_essence_compression,
962 essence_compression);
965 g_strdup_printf ("audio/x-mxf-%s-%s", essence_container,
966 essence_compression);
967 } else if (track->parent.type == MXF_METADATA_TRACK_DATA_ESSENCE) {
968 if (MXF_IS_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (track->parent.
970 mxf_ul_to_string (&MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR
971 (track->parent.descriptor[0])->data_essence_coding,
972 essence_compression);
975 g_strdup_printf ("application/x-mxf-%s-%s", essence_container,
976 essence_compression);
979 g_assert_not_reached ();
982 caps = gst_caps_new_empty_simple (name);
984 etrack->intra_only = FALSE;
987 etrack->handler->create_caps (track, &etrack->tags,
988 &etrack->intra_only, &etrack->handle_func, &etrack->mapping_data);
991 GST_DEBUG_OBJECT (demux, "Created caps %" GST_PTR_FORMAT, caps);
994 GST_WARNING_OBJECT (demux, "No caps created, ignoring stream");
995 g_free (etrack->mapping_data);
996 etrack->mapping_data = NULL;
998 gst_tag_list_unref (etrack->tags);
1002 GST_WARNING_OBJECT (demux, "Couldn't create updated caps for stream");
1003 } else if (!etrack->caps || !gst_caps_is_equal (etrack->caps, caps)) {
1005 gst_caps_unref (etrack->caps);
1006 etrack->caps = caps;
1008 gst_caps_unref (caps);
1012 etrack->min_edit_units = 1;
1013 /* Ensure we don't output one buffer per sample for audio */
1014 if (gst_util_uint64_scale (GST_SECOND, track->edit_rate.d,
1015 track->edit_rate.n) < 10 * GST_MSECOND) {
1016 GstStructure *s = gst_caps_get_structure (etrack->caps, 0);
1017 const gchar *name = gst_structure_get_name (s);
1018 if (g_str_has_prefix (name, "audio/x-raw")) {
1019 etrack->min_edit_units =
1020 gst_util_uint64_scale (25 * GST_MSECOND, track->edit_rate.n,
1021 track->edit_rate.d * GST_SECOND);
1022 GST_DEBUG_OBJECT (demux, "Seting miminum number of edit units to %u",
1023 etrack->min_edit_units);
1027 /* FIXME : We really should just abort/ignore the stream completely if we
1028 * don't have a handler for it */
1029 if (etrack->handler != NULL)
1030 etrack->wrapping = etrack->handler->get_track_wrapping (track);
1032 etrack->wrapping = MXF_ESSENCE_WRAPPING_UNKNOWN_WRAPPING;
1034 if (package->is_interleaved) {
1035 GST_DEBUG_OBJECT (demux,
1036 "track comes from interleaved source package with %d track(s), setting delta_id to -1",
1037 package->parent.n_tracks);
1038 if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
1039 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1040 ("Non-frame-wrapping is not allowed in interleaved File Package."));
1041 return GST_FLOW_ERROR;
1043 etrack->delta_id = MXF_INDEX_DELTA_ID_UNKNOWN;
1045 etrack->delta_id = MXF_INDEX_DELTA_ID_UNKNOWN;
1047 etrack->source_package = package;
1048 etrack->source_track = track;
1053 g_free (etrack->mapping_data);
1055 gst_tag_list_unref (etrack->tags);
1057 gst_caps_unref (etrack->caps);
1059 g_array_remove_index (demux->essence_tracks,
1060 demux->essence_tracks->len - 1);
1065 if (demux->essence_tracks->len == 0) {
1066 GST_ERROR_OBJECT (demux, "No valid essence tracks in this file");
1067 return GST_FLOW_ERROR;
1070 for (i = 0; i < demux->essence_tracks->len; i++) {
1071 GstMXFDemuxEssenceTrack *etrack =
1072 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
1074 if (!etrack->source_package || !etrack->source_track || !etrack->caps) {
1075 GST_ERROR_OBJECT (demux, "Failed to update essence track %u", i);
1076 return GST_FLOW_ERROR;
1084 static MXFMetadataEssenceContainerData *
1085 essence_container_for_source_package (MXFMetadataContentStorage * storage,
1086 MXFMetadataSourcePackage * package)
1090 for (i = 0; i < storage->n_essence_container_data; i++) {
1091 MXFMetadataEssenceContainerData *cont = storage->essence_container_data[i];
1092 if (cont && cont->linked_package == package)
1100 gst_mxf_demux_show_topology (GstMXFDemux * demux)
1102 GList *material_packages = NULL;
1103 GList *file_packages = NULL;
1105 MXFMetadataContentStorage *storage = demux->preface->content_storage;
1109 /* Show the topology starting from the preface */
1110 GST_DEBUG_OBJECT (demux, "Topology");
1112 for (i = 0; i < storage->n_packages; i++) {
1113 MXFMetadataGenericPackage *pack = storage->packages[i];
1114 if (MXF_IS_METADATA_MATERIAL_PACKAGE (pack))
1115 material_packages = g_list_append (material_packages, pack);
1116 else if (MXF_IS_METADATA_SOURCE_PACKAGE (pack))
1117 file_packages = g_list_append (file_packages, pack);
1119 GST_DEBUG_OBJECT (demux, "Unknown package type");
1122 GST_DEBUG_OBJECT (demux, "Number of Material Package (i.e. output) : %d",
1123 g_list_length (material_packages));
1124 for (tmp = material_packages; tmp; tmp = tmp->next) {
1125 MXFMetadataMaterialPackage *pack = (MXFMetadataMaterialPackage *) tmp->data;
1126 GST_DEBUG_OBJECT (demux, " Package with %d tracks , UID:%s",
1127 pack->n_tracks, mxf_umid_to_string (&pack->package_uid, str));
1128 for (i = 0; i < pack->n_tracks; i++) {
1129 MXFMetadataTrack *track = pack->tracks[i];
1130 if (track == NULL) {
1131 GST_DEBUG_OBJECT (demux, " Unknown/Unhandled track UUID %s",
1132 mxf_uuid_to_string (&pack->tracks_uids[i], str));
1133 } else if (MXF_IS_METADATA_TIMELINE_TRACK (track)) {
1134 MXFMetadataTimelineTrack *mtrack = (MXFMetadataTimelineTrack *) track;
1135 GST_DEBUG_OBJECT (demux,
1136 " Timeline Track id:%d number:0x%08x name:`%s` edit_rate:%d/%d origin:%"
1137 G_GINT64_FORMAT, track->track_id, track->track_number,
1138 track->track_name, mtrack->edit_rate.n, mtrack->edit_rate.d,
1141 GST_DEBUG_OBJECT (demux,
1142 " Non-Timeline-Track id:%d number:0x%08x name:`%s`",
1143 track->track_id, track->track_number, track->track_name);
1146 MXFMetadataSequence *sequence = track->sequence;
1148 GST_DEBUG_OBJECT (demux,
1149 " Sequence duration:%" G_GINT64_FORMAT
1150 " n_structural_components:%d", sequence->duration,
1151 sequence->n_structural_components);
1152 for (si = 0; si < sequence->n_structural_components; si++) {
1153 MXFMetadataStructuralComponent *comp =
1154 sequence->structural_components[si];
1155 GST_DEBUG_OBJECT (demux,
1156 " Component #%d duration:%" G_GINT64_FORMAT, si,
1158 if (MXF_IS_METADATA_SOURCE_CLIP (comp)) {
1159 MXFMetadataSourceClip *clip = (MXFMetadataSourceClip *) comp;
1160 GST_DEBUG_OBJECT (demux,
1161 " Clip start_position:%" G_GINT64_FORMAT
1162 " source_track_id:%d source_package_id:%s",
1163 clip->start_position, clip->source_track_id,
1164 mxf_umid_to_string (&clip->source_package_id, str));
1172 GST_DEBUG_OBJECT (demux, "Number of File Packages (i.e. input) : %d",
1173 g_list_length (file_packages));
1174 for (tmp = file_packages; tmp; tmp = tmp->next) {
1175 MXFMetadataMaterialPackage *pack = (MXFMetadataMaterialPackage *) tmp->data;
1176 MXFMetadataSourcePackage *src = (MXFMetadataSourcePackage *) pack;
1177 MXFMetadataEssenceContainerData *econt =
1178 essence_container_for_source_package (storage, src);
1179 GST_DEBUG_OBJECT (demux,
1180 " Package (body_sid:%d index_sid:%d top_level:%d) with %d tracks , UID:%s",
1181 econt->body_sid, econt->index_sid, src->top_level, pack->n_tracks,
1182 mxf_umid_to_string (&pack->package_uid, str));
1183 GST_DEBUG_OBJECT (demux, " Package descriptor : %s",
1184 g_type_name (G_OBJECT_TYPE (src->descriptor)));
1185 for (i = 0; i < pack->n_tracks; i++) {
1186 MXFMetadataTrack *track = pack->tracks[i];
1187 MXFMetadataSequence *sequence = track->sequence;
1189 if (MXF_IS_METADATA_TIMELINE_TRACK (track)) {
1190 MXFMetadataTimelineTrack *mtrack = (MXFMetadataTimelineTrack *) track;
1191 GST_DEBUG_OBJECT (demux,
1192 " Timeline Track id:%d number:0x%08x name:`%s` edit_rate:%d/%d origin:%"
1193 G_GINT64_FORMAT, track->track_id, track->track_number,
1194 track->track_name, mtrack->edit_rate.n, mtrack->edit_rate.d,
1197 GST_DEBUG_OBJECT (demux,
1198 " Non-Timeline-Track id:%d number:0x%08x name:`%s` type:0x%x",
1199 track->track_id, track->track_number, track->track_name,
1202 for (di = 0; di < track->n_descriptor; di++) {
1203 MXFMetadataFileDescriptor *desc = track->descriptor[di];
1204 GST_DEBUG_OBJECT (demux, " Descriptor %s %s",
1205 g_type_name (G_OBJECT_TYPE (desc)),
1206 mxf_ul_to_string (&desc->essence_container, str));
1208 GST_DEBUG_OBJECT (demux,
1209 " Sequence duration:%" G_GINT64_FORMAT
1210 " n_structural_components:%d", sequence->duration,
1211 sequence->n_structural_components);
1212 for (si = 0; si < sequence->n_structural_components; si++) {
1213 MXFMetadataStructuralComponent *comp =
1214 sequence->structural_components[si];
1215 GST_DEBUG_OBJECT (demux,
1216 " Component #%d duration:%" G_GINT64_FORMAT, si,
1222 g_list_free (material_packages);
1223 g_list_free (file_packages);
1226 static GstFlowReturn
1227 gst_mxf_demux_update_tracks (GstMXFDemux * demux)
1229 MXFMetadataGenericPackage *current_package = NULL;
1232 guint component_index;
1234 GList *pads = NULL, *l;
1235 GstVideoTimeCode start_timecode = GST_VIDEO_TIME_CODE_INIT;
1237 g_rw_lock_writer_lock (&demux->metadata_lock);
1238 GST_DEBUG_OBJECT (demux, "Updating tracks");
1240 gst_mxf_demux_show_topology (demux);
1242 if ((ret = gst_mxf_demux_update_essence_tracks (demux)) != GST_FLOW_OK) {
1246 current_package = gst_mxf_demux_choose_package (demux);
1248 if (!current_package) {
1249 GST_ERROR_OBJECT (demux, "Unable to find current package");
1250 ret = GST_FLOW_ERROR;
1252 } else if (!current_package->tracks) {
1253 GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks");
1254 ret = GST_FLOW_ERROR;
1256 } else if (!current_package->n_essence_tracks) {
1257 GST_ERROR_OBJECT (demux, "Current package has no essence tracks");
1258 ret = GST_FLOW_ERROR;
1262 first_run = (demux->src->len == 0);
1264 /* For material packages, there must be one timecode track with one
1265 * continuous timecode. For source packages there might be multiple,
1266 * discontinuous timecode components.
1267 * TODO: Support multiple timecode components
1269 for (i = 0; i < current_package->n_tracks; i++) {
1270 MXFMetadataTimelineTrack *track = NULL;
1271 MXFMetadataSequence *sequence = NULL;
1272 MXFMetadataTimecodeComponent *component = NULL;
1274 if (!current_package->tracks[i]) {
1275 GST_WARNING_OBJECT (demux, "Unresolved track");
1279 if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
1280 GST_DEBUG_OBJECT (demux, "Skipping Non-timeline track");
1285 track = MXF_METADATA_TIMELINE_TRACK (current_package->tracks[i]);
1287 if (!track->parent.sequence)
1289 sequence = track->parent.sequence;
1290 if (sequence->n_structural_components != 1 ||
1291 !sequence->structural_components[0]
1293 !MXF_IS_METADATA_TIMECODE_COMPONENT (sequence->structural_components
1298 MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1300 /* Not a timecode track */
1301 if (track->parent.type && (track->parent.type & 0xf0) != 0x10)
1304 /* Main timecode track must have id 1, all others must be 0 */
1305 if (track->parent.track_id != 1)
1308 gst_video_time_code_init (&start_timecode, track->edit_rate.n,
1309 track->edit_rate.d, NULL, (component->drop_frame
1311 GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME
1312 : GST_VIDEO_TIME_CODE_FLAGS_NONE), 0, 0, 0, 0, 0);
1313 gst_video_time_code_add_frames (&start_timecode, track->origin);
1314 gst_video_time_code_add_frames (&start_timecode, component->start_timecode);
1318 for (i = 0; i < current_package->n_tracks; i++) {
1319 MXFMetadataTimelineTrack *track = NULL;
1320 MXFMetadataSequence *sequence;
1321 MXFMetadataSourceClip *component = NULL;
1322 MXFMetadataSourcePackage *source_package = NULL;
1323 MXFMetadataTimelineTrack *source_track = NULL;
1324 GstMXFDemuxEssenceTrack *etrack = NULL;
1325 GstMXFDemuxPad *pad = NULL;
1328 GST_DEBUG_OBJECT (demux, "Handling track %u", i);
1330 if (!current_package->tracks[i]) {
1331 GST_WARNING_OBJECT (demux, "Unresolved track");
1335 if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
1336 GST_DEBUG_OBJECT (demux, "No timeline track");
1340 track = MXF_METADATA_TIMELINE_TRACK (current_package->tracks[i]);
1343 /* Find pad from track_id */
1344 for (j = 0; j < demux->src->len; j++) {
1345 GstMXFDemuxPad *tmp = g_ptr_array_index (demux->src, j);
1347 if (tmp->track_id == track->parent.track_id) {
1355 component_index = pad->current_component_index;
1357 component_index = 0;
1359 if (!track->parent.sequence) {
1360 GST_WARNING_OBJECT (demux, "Track with no sequence");
1364 ret = GST_FLOW_ERROR;
1369 sequence = track->parent.sequence;
1371 if (MXF_IS_METADATA_SOURCE_PACKAGE (current_package)) {
1372 GST_DEBUG_OBJECT (demux, "Playing source package");
1375 source_package = MXF_METADATA_SOURCE_PACKAGE (current_package);
1376 source_track = track;
1377 } else if (sequence->structural_components
1379 MXF_IS_METADATA_SOURCE_CLIP (sequence->structural_components
1380 [component_index])) {
1381 GST_DEBUG_OBJECT (demux, "Playing material package");
1384 MXF_METADATA_SOURCE_CLIP (sequence->structural_components
1387 GST_WARNING_OBJECT (demux, "NULL component in non-source package");
1391 ret = GST_FLOW_ERROR;
1396 if (component->source_package && component->source_package->top_level &&
1397 MXF_METADATA_GENERIC_PACKAGE (component->source_package)->tracks) {
1398 MXFMetadataGenericPackage *tmp_pkg =
1399 MXF_METADATA_GENERIC_PACKAGE (component->source_package);
1401 source_package = component->source_package;
1403 for (k = 0; k < tmp_pkg->n_tracks; k++) {
1404 MXFMetadataTrack *tmp = tmp_pkg->tracks[k];
1406 if (tmp->track_id == component->source_track_id) {
1407 source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1414 if (track->parent.type && (track->parent.type & 0xf0) != 0x30) {
1415 GST_DEBUG_OBJECT (demux,
1416 "No essence track. type:0x%02x track_id:%d track_number:0x%08x",
1417 track->parent.type, track->parent.track_id,
1418 track->parent.track_number);
1422 ret = GST_FLOW_ERROR;
1427 if (!source_package || track->parent.type == MXF_METADATA_TRACK_UNKNOWN
1429 GST_WARNING_OBJECT (demux,
1430 "No source package or track type for track found");
1434 ret = GST_FLOW_ERROR;
1439 for (k = 0; k < demux->essence_tracks->len; k++) {
1440 GstMXFDemuxEssenceTrack *tmp =
1441 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, k);
1443 if (tmp->source_package == source_package &&
1444 tmp->source_track == source_track) {
1451 GST_WARNING_OBJECT (demux, "No essence track for this track found");
1455 ret = GST_FLOW_ERROR;
1460 if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0 ||
1461 source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1462 GST_WARNING_OBJECT (demux, "Track has an invalid edit rate");
1466 ret = GST_FLOW_ERROR;
1471 if (MXF_IS_METADATA_MATERIAL_PACKAGE (current_package) && !component) {
1472 GST_WARNING_OBJECT (demux,
1473 "Playing material package but found no component for track");
1477 ret = GST_FLOW_ERROR;
1482 if (!source_package->descriptor) {
1483 GST_WARNING_OBJECT (demux, "Source package has no descriptors");
1487 ret = GST_FLOW_ERROR;
1492 if (!source_track->parent.descriptor) {
1493 GST_WARNING_OBJECT (demux, "No descriptor found for track");
1497 ret = GST_FLOW_ERROR;
1502 if (!pad && first_run) {
1503 GstPadTemplate *templ;
1507 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
1509 pad_name = g_strdup_printf ("track_%u", track->parent.track_id);
1511 g_assert (templ != NULL);
1514 pad = (GstMXFDemuxPad *) g_object_new (GST_TYPE_MXF_DEMUX_PAD,
1515 "name", pad_name, "direction", GST_PAD_SRC, "template", templ, NULL);
1516 pad->need_segment = TRUE;
1521 pad->tags = gst_tag_list_copy (demux->tags);
1525 GST_WARNING_OBJECT (demux,
1526 "Not the first pad addition run, ignoring new track");
1531 pad->track_id = track->parent.track_id;
1533 pad->material_package = current_package;
1534 pad->material_track = track;
1536 pad->start_timecode = start_timecode;
1538 /* If we just added the pad initialize for the current component */
1539 if (first_run && MXF_IS_METADATA_MATERIAL_PACKAGE (current_package)) {
1540 pad->current_component_index = 0;
1541 pad->current_component_start = source_track->origin;
1542 pad->current_component_start_position = 0;
1544 if (component->parent.duration >= -1)
1545 pad->current_component_duration = component->parent.duration;
1547 pad->current_component_duration = -1;
1549 if (track->edit_rate.n != source_track->edit_rate.n ||
1550 track->edit_rate.d != source_track->edit_rate.d) {
1551 pad->current_component_start +=
1552 gst_util_uint64_scale (component->start_position,
1553 source_track->edit_rate.n * track->edit_rate.d,
1554 source_track->edit_rate.d * track->edit_rate.n);
1556 if (pad->current_component_duration != -1)
1557 pad->current_component_duration =
1558 gst_util_uint64_scale (pad->current_component_duration,
1559 source_track->edit_rate.n * track->edit_rate.d,
1560 source_track->edit_rate.d * track->edit_rate.n);
1562 pad->current_component_start += component->start_position;
1564 pad->current_essence_track_position = pad->current_component_start;
1567 /* NULL iff playing a source package */
1568 pad->current_component = component;
1570 pad->current_essence_track = etrack;
1574 gst_tag_list_insert (pad->tags, etrack->tags, GST_TAG_MERGE_REPLACE);
1576 pad->tags = gst_tag_list_copy (etrack->tags);
1579 pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1580 if (pad_caps && !gst_caps_is_equal (pad_caps, etrack->caps)) {
1581 gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1582 } else if (!pad_caps) {
1586 gst_pad_set_event_function (GST_PAD_CAST (pad),
1587 GST_DEBUG_FUNCPTR (gst_mxf_demux_src_event));
1589 gst_pad_set_query_function (GST_PAD_CAST (pad),
1590 GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query));
1592 gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
1593 gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
1596 gst_pad_create_stream_id_printf (GST_PAD_CAST (pad),
1597 GST_ELEMENT_CAST (demux), "%03u", pad->track_id);
1600 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
1602 if (gst_event_parse_group_id (event, &demux->group_id))
1603 demux->have_group_id = TRUE;
1605 demux->have_group_id = FALSE;
1606 gst_event_unref (event);
1607 } else if (!demux->have_group_id) {
1608 demux->have_group_id = TRUE;
1609 demux->group_id = gst_util_group_id_next ();
1611 event = gst_event_new_stream_start (stream_id);
1612 if (demux->have_group_id)
1613 gst_event_set_group_id (event, demux->group_id);
1615 gst_pad_push_event (GST_PAD_CAST (pad), event);
1618 gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1620 pads = g_list_prepend (pads, gst_object_ref (pad));
1622 g_ptr_array_add (demux->src, pad);
1623 pad->discont = TRUE;
1626 gst_caps_unref (pad_caps);
1629 if (demux->src->len > 0) {
1630 for (i = 0; i < demux->src->len; i++) {
1631 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
1633 if (!pad->material_track || !pad->material_package) {
1634 GST_ERROR_OBJECT (demux, "Unable to update existing pad");
1635 ret = GST_FLOW_ERROR;
1640 GST_ERROR_OBJECT (demux, "Couldn't create any streams");
1641 ret = GST_FLOW_ERROR;
1645 g_rw_lock_writer_unlock (&demux->metadata_lock);
1647 for (l = pads; l; l = l->next) {
1648 gst_flow_combiner_add_pad (demux->flowcombiner, l->data);
1649 gst_element_add_pad (GST_ELEMENT_CAST (demux), l->data);
1654 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1656 /* Re-check all existing partitions for source package linking in case the
1657 * header partition contains data (allowed in early MXF versions) */
1658 for (l = demux->partitions; l; l = l->next)
1659 gst_mxf_demux_partition_postcheck (demux, (GstMXFDemuxPartition *) l->data);
1664 g_rw_lock_writer_unlock (&demux->metadata_lock);
1668 static GstFlowReturn
1669 gst_mxf_demux_handle_metadata (GstMXFDemux * demux, GstMXFKLV * klv)
1672 MXFMetadata *metadata = NULL, *old = NULL;
1674 GstFlowReturn ret = GST_FLOW_OK;
1676 type = GST_READ_UINT16_BE (&klv->key.u[13]);
1678 GST_DEBUG_OBJECT (demux,
1679 "Handling metadata of size %" G_GSIZE_FORMAT " at offset %"
1680 G_GUINT64_FORMAT " of type 0x%04x", klv->length, klv->offset, type);
1682 if (G_UNLIKELY (!demux->current_partition)) {
1683 GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1684 return GST_FLOW_ERROR;
1687 if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1688 GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1689 return GST_FLOW_ERROR;
1692 if (demux->current_partition->parsed_metadata) {
1693 GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1697 if (klv->length == 0)
1699 ret = gst_mxf_demux_fill_klv (demux, klv);
1700 if (ret != GST_FLOW_OK)
1703 gst_buffer_map (klv->data, &map, GST_MAP_READ);
1705 mxf_metadata_new (type, &demux->current_partition->primer, demux->offset,
1706 map.data, map.size);
1707 gst_buffer_unmap (klv->data, &map);
1710 GST_WARNING_OBJECT (demux,
1711 "Unknown or unhandled metadata of type 0x%04x", type);
1716 g_hash_table_lookup (demux->metadata,
1717 &MXF_METADATA_BASE (metadata)->instance_uid);
1719 if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (metadata)) {
1720 #ifndef GST_DISABLE_GST_DEBUG
1724 GST_DEBUG_OBJECT (demux,
1725 "Metadata with instance uid %s already exists and has different type '%s',"
1727 mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str),
1728 g_type_name (G_TYPE_FROM_INSTANCE (old)),
1729 g_type_name (G_TYPE_FROM_INSTANCE (metadata)));
1730 g_object_unref (metadata);
1731 return GST_FLOW_ERROR;
1733 && MXF_METADATA_BASE (old)->offset >=
1734 MXF_METADATA_BASE (metadata)->offset) {
1735 #ifndef GST_DISABLE_GST_DEBUG
1739 GST_DEBUG_OBJECT (demux,
1740 "Metadata with instance uid %s already exists and is newer",
1741 mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str));
1742 g_object_unref (metadata);
1746 g_rw_lock_writer_lock (&demux->metadata_lock);
1747 demux->update_metadata = TRUE;
1749 if (MXF_IS_METADATA_PREFACE (metadata)) {
1750 demux->preface = MXF_METADATA_PREFACE (metadata);
1753 gst_mxf_demux_reset_linked_metadata (demux);
1755 g_hash_table_replace (demux->metadata,
1756 &MXF_METADATA_BASE (metadata)->instance_uid, metadata);
1757 g_rw_lock_writer_unlock (&demux->metadata_lock);
1762 static GstFlowReturn
1763 gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux, GstMXFKLV * klv)
1768 GstFlowReturn ret = GST_FLOW_OK;
1769 MXFDescriptiveMetadata *m = NULL, *old = NULL;
1771 scheme = GST_READ_UINT8 (&klv->key.u[12]);
1772 type = GST_READ_UINT24_BE (&klv->key.u[13]);
1774 GST_DEBUG_OBJECT (demux,
1775 "Handling descriptive metadata of size %" G_GSIZE_FORMAT " at offset %"
1776 G_GUINT64_FORMAT " with scheme 0x%02x and type 0x%06x",
1777 klv->length, klv->offset, scheme, type);
1779 if (G_UNLIKELY (!demux->current_partition)) {
1780 GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1781 return GST_FLOW_ERROR;
1784 if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1785 GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1786 return GST_FLOW_ERROR;
1789 if (demux->current_partition->parsed_metadata) {
1790 GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1794 ret = gst_mxf_demux_fill_klv (demux, klv);
1795 if (ret != GST_FLOW_OK)
1798 gst_buffer_map (klv->data, &map, GST_MAP_READ);
1799 m = mxf_descriptive_metadata_new (scheme, type,
1800 &demux->current_partition->primer, demux->offset, map.data, map.size);
1801 gst_buffer_unmap (klv->data, &map);
1804 GST_WARNING_OBJECT (demux,
1805 "Unknown or unhandled descriptive metadata of scheme 0x%02x and type 0x%06x",
1811 g_hash_table_lookup (demux->metadata,
1812 &MXF_METADATA_BASE (m)->instance_uid);
1814 if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (m)) {
1815 #ifndef GST_DISABLE_GST_DEBUG
1819 GST_DEBUG_OBJECT (demux,
1820 "Metadata with instance uid %s already exists and has different type '%s',"
1822 mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str),
1823 g_type_name (G_TYPE_FROM_INSTANCE (old)),
1824 g_type_name (G_TYPE_FROM_INSTANCE (m)));
1826 return GST_FLOW_ERROR;
1828 && MXF_METADATA_BASE (old)->offset >= MXF_METADATA_BASE (m)->offset) {
1829 #ifndef GST_DISABLE_GST_DEBUG
1833 GST_DEBUG_OBJECT (demux,
1834 "Metadata with instance uid %s already exists and is newer",
1835 mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str));
1840 g_rw_lock_writer_lock (&demux->metadata_lock);
1842 demux->update_metadata = TRUE;
1843 gst_mxf_demux_reset_linked_metadata (demux);
1845 g_hash_table_replace (demux->metadata, &MXF_METADATA_BASE (m)->instance_uid,
1848 g_rw_lock_writer_unlock (&demux->metadata_lock);
1853 static GstFlowReturn
1854 gst_mxf_demux_handle_generic_container_system_item (GstMXFDemux * demux,
1857 GST_DEBUG_OBJECT (demux,
1858 "Handling generic container system item of size %" G_GSIZE_FORMAT
1859 " at offset %" G_GUINT64_FORMAT, klv->length, klv->offset);
1861 if (demux->current_partition->essence_container_offset == 0)
1862 demux->current_partition->essence_container_offset =
1863 demux->offset - demux->current_partition->partition.this_partition -
1866 /* TODO: parse this */
1870 static GstFlowReturn
1871 gst_mxf_demux_pad_set_component (GstMXFDemux * demux, GstMXFDemuxPad * pad,
1874 GstFlowReturn ret = GST_FLOW_OK;
1876 MXFMetadataSequence *sequence;
1878 MXFMetadataSourcePackage *source_package = NULL;
1879 MXFMetadataTimelineTrack *source_track = NULL;
1880 gboolean update = (pad->current_component_index != i);
1882 pad->current_component_index = i;
1884 sequence = pad->material_track->parent.sequence;
1886 if (pad->current_component_index >= sequence->n_structural_components) {
1887 GST_DEBUG_OBJECT (demux, "After last structural component");
1888 pad->current_component_index = sequence->n_structural_components - 1;
1892 GST_DEBUG_OBJECT (demux, "Switching to component %u",
1893 pad->current_component_index);
1895 pad->current_component =
1896 MXF_METADATA_SOURCE_CLIP (sequence->structural_components[pad->
1897 current_component_index]);
1898 if (pad->current_component == NULL) {
1899 GST_ERROR_OBJECT (demux, "No such structural component");
1900 return GST_FLOW_ERROR;
1903 if (!pad->current_component->source_package
1904 || !pad->current_component->source_package->top_level
1905 || !MXF_METADATA_GENERIC_PACKAGE (pad->current_component->
1906 source_package)->tracks) {
1907 GST_ERROR_OBJECT (demux, "Invalid component");
1908 return GST_FLOW_ERROR;
1911 source_package = pad->current_component->source_package;
1913 for (k = 0; k < source_package->parent.n_tracks; k++) {
1914 MXFMetadataTrack *tmp = source_package->parent.tracks[k];
1916 if (tmp->track_id == pad->current_component->source_track_id) {
1917 source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1922 if (!source_track) {
1923 GST_ERROR_OBJECT (demux, "No source track found");
1924 return GST_FLOW_ERROR;
1927 pad->current_essence_track = NULL;
1929 for (k = 0; k < demux->essence_tracks->len; k++) {
1930 GstMXFDemuxEssenceTrack *tmp =
1931 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, k);
1933 if (tmp->source_package == source_package &&
1934 tmp->source_track == source_track) {
1935 pad->current_essence_track = tmp;
1940 if (!pad->current_essence_track) {
1941 GST_ERROR_OBJECT (demux, "No corresponding essence track found");
1942 return GST_FLOW_ERROR;
1945 if (!source_package->descriptor) {
1946 GST_ERROR_OBJECT (demux, "Source package has no descriptors");
1947 return GST_FLOW_ERROR;
1950 if (!source_track->parent.descriptor) {
1951 GST_ERROR_OBJECT (demux, "No descriptor found for track");
1952 return GST_FLOW_ERROR;
1955 if (source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1956 GST_ERROR_OBJECT (demux, "Source track has invalid edit rate");
1957 return GST_FLOW_ERROR;
1960 pad->current_component_start_position = 0;
1961 for (k = 0; k < i; k++) {
1962 pad->current_component_start_position +=
1963 MXF_METADATA_SOURCE_CLIP (sequence->structural_components[k])->
1967 if (pad->current_component->parent.duration >= -1)
1968 pad->current_component_duration = pad->current_component->parent.duration;
1970 pad->current_component_duration = -1;
1972 if (pad->material_track->edit_rate.n != source_track->edit_rate.n ||
1973 pad->material_track->edit_rate.d != source_track->edit_rate.d) {
1974 pad->current_component_start +=
1975 gst_util_uint64_scale (pad->current_component->start_position,
1976 source_track->edit_rate.n * pad->material_track->edit_rate.d,
1977 source_track->edit_rate.d * pad->material_track->edit_rate.n);
1979 if (pad->current_component_duration != -1)
1980 pad->current_component_duration =
1981 gst_util_uint64_scale (pad->current_component_duration,
1982 source_track->edit_rate.n * pad->material_track->edit_rate.d,
1983 source_track->edit_rate.d * pad->material_track->edit_rate.n);
1985 pad->current_component_start += pad->current_component->start_position;
1987 pad->current_essence_track_position = pad->current_component_start;
1989 pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1991 || !gst_caps_is_equal (pad_caps, pad->current_essence_track->caps)) {
1992 gst_pad_set_caps (GST_PAD_CAST (pad), pad->current_essence_track->caps);
1995 gst_caps_unref (pad_caps);
1999 if (pad->current_essence_track->tags)
2000 gst_tag_list_insert (pad->tags, pad->current_essence_track->tags,
2001 GST_TAG_MERGE_REPLACE);
2003 if (pad->current_essence_track->tags)
2004 pad->tags = gst_tag_list_copy (pad->current_essence_track->tags);
2008 if (ret == GST_FLOW_EOS) {
2009 pad->current_essence_track_position += pad->current_component_duration;
2016 * Find the partition containing the stream offset of the given track
2018 static GstMXFDemuxPartition *
2019 get_partition_for_stream_offset (GstMXFDemux * demux,
2020 GstMXFDemuxEssenceTrack * etrack, guint64 stream_offset)
2023 GstMXFDemuxPartition *offset_partition = NULL, *next_partition = NULL;
2025 for (tmp = demux->partitions; tmp; tmp = tmp->next) {
2026 GstMXFDemuxPartition *partition = tmp->data;
2028 if (!next_partition && offset_partition)
2029 next_partition = partition;
2031 if (partition->partition.body_sid != etrack->body_sid)
2033 if (partition->partition.body_offset > stream_offset)
2036 offset_partition = partition;
2037 next_partition = NULL;
2040 if (offset_partition
2041 && stream_offset < offset_partition->partition.body_offset)
2044 GST_DEBUG_OBJECT (demux,
2045 "Found this_partition:%" G_GUINT64_FORMAT " body_offset:%"
2046 G_GUINT64_FORMAT, offset_partition->partition.this_partition,
2047 offset_partition->partition.body_offset);
2049 /* Are we overriding into the next partition ? */
2050 if (next_partition) {
2051 guint64 partition_essence_size =
2052 next_partition->partition.this_partition -
2053 offset_partition->partition.this_partition +
2054 offset_partition->essence_container_offset;
2055 guint64 in_partition =
2056 stream_offset - offset_partition->partition.body_offset;
2057 GST_DEBUG_OBJECT (demux,
2058 "Followed by this_partition:%" G_GUINT64_FORMAT " body_offset:%"
2059 G_GUINT64_FORMAT, next_partition->partition.this_partition,
2060 next_partition->partition.body_offset);
2062 if (in_partition >= partition_essence_size) {
2063 GST_WARNING_OBJECT (demux,
2064 "stream_offset %" G_GUINT64_FORMAT
2065 " in track body_sid:% index_sid:%d leaks into next unrelated partition (body_sid:%d / index_sid:%d)",
2066 stream_offset, etrack->body_sid, etrack->index_sid,
2067 next_partition->partition.body_sid,
2068 next_partition->partition.index_sid);
2072 return offset_partition;
2075 static GstMXFDemuxIndexTable *
2076 get_track_index_table (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack)
2080 /* Look in the indextables */
2081 for (l = demux->index_tables; l; l = l->next) {
2082 GstMXFDemuxIndexTable *tmp = l->data;
2084 if (tmp->body_sid == etrack->body_sid
2085 && tmp->index_sid == etrack->index_sid) {
2094 get_track_max_temporal_offset (GstMXFDemux * demux,
2095 GstMXFDemuxEssenceTrack * etrack)
2097 GstMXFDemuxIndexTable *table;
2099 if (etrack->intra_only)
2102 table = get_track_index_table (demux, etrack);
2105 return table->max_temporal_offset;
2110 find_offset (GArray * offsets, gint64 * position, gboolean keyframe)
2112 GstMXFDemuxIndex *idx;
2113 guint64 current_offset = -1;
2114 gint64 current_position = *position;
2116 if (!offsets || offsets->len <= *position)
2119 idx = &g_array_index (offsets, GstMXFDemuxIndex, *position);
2120 if (idx->offset != 0 && (!keyframe || idx->keyframe)) {
2121 current_offset = idx->offset;
2122 } else if (idx->offset != 0) {
2124 while (current_position >= 0) {
2125 GST_LOG ("current_position %" G_GINT64_FORMAT, current_position);
2126 idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
2127 if (idx->offset == 0) {
2128 GST_LOG ("breaking offset 0");
2130 } else if (!idx->keyframe) {
2134 GST_LOG ("Breaking found offset");
2135 current_offset = idx->offset;
2141 if (current_offset == -1)
2144 *position = current_position;
2145 return current_offset;
2150 * @demux: The demuxer
2151 * @etrack: The target essence track
2152 * @position: An edit unit position
2153 * @keyframe: if TRUE search for supporting keyframe
2154 * @entry: (out): Will be filled with the matching entry information
2156 * Finds the edit entry of @etrack for the given edit unit @position and fill
2157 * @entry with the information about that edit entry. If @keyframe is TRUE, the
2158 * supporting entry (i.e. keyframe) for the given position will be searched for.
2160 * For frame-wrapped contents, the returned offset will be the position of the
2161 * KLV of the content. For clip-wrapped content, the returned offset will be the
2162 * position of the essence (i.e. without KLV header) and the entry will specify
2163 * the size (in bytes).
2165 * The returned entry will also specify the duration (in edit units) of the
2166 * content, which can be different from 1 for special cases (such as raw audio
2167 * where multiple samples could be aggregated).
2169 * Returns: TRUE if the entry was found and @entry was properly filled, else
2173 find_edit_entry (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack,
2174 gint64 position, gboolean keyframe, GstMXFDemuxIndex * entry)
2176 GstMXFDemuxIndexTable *index_table = NULL;
2178 MXFIndexTableSegment *segment = NULL;
2179 GstMXFDemuxPartition *offset_partition = NULL;
2180 guint64 stream_offset = G_MAXUINT64, absolute_offset;
2182 GST_DEBUG_OBJECT (demux,
2183 "track %d body_sid:%d index_sid:%d delta_id:%d position:%" G_GINT64_FORMAT
2184 " keyframe:%d", etrack->track_id, etrack->body_sid,
2185 etrack->index_sid, etrack->delta_id, position, keyframe);
2187 /* Default values */
2188 entry->duration = 1;
2189 /* By default every entry is a keyframe unless specified otherwise */
2190 entry->keyframe = TRUE;
2192 /* Look in the track offsets */
2193 if (etrack->offsets && etrack->offsets->len > position) {
2194 if (find_offset (etrack->offsets, &position, keyframe) != -1) {
2195 *entry = g_array_index (etrack->offsets, GstMXFDemuxIndex, position);
2196 GST_LOG_OBJECT (demux, "Found entry in track offsets");
2199 GST_LOG_OBJECT (demux, "Didn't find entry in track offsets");
2202 /* Look in the indextables */
2203 index_table = get_track_index_table (demux, etrack);
2206 GST_DEBUG_OBJECT (demux,
2207 "Couldn't find index table for body_sid:%d index_sid:%d",
2208 etrack->body_sid, etrack->index_sid);
2212 GST_DEBUG_OBJECT (demux,
2213 "Looking for position %" G_GINT64_FORMAT
2214 " in index table (max temporal offset %u)",
2215 etrack->position, index_table->max_temporal_offset);
2217 /* Searching for a position in index tables works in 3 steps:
2219 * 1. Figure out the table segment containing that position
2220 * 2. Figure out the "stream offset" (and additional flags/timing) of that
2221 * position from the table segment.
2222 * 3. Figure out the "absolute offset" of that "stream offset" using partitions
2227 /* Find matching index segment */
2228 GST_DEBUG_OBJECT (demux, "Look for entry in %d segments",
2229 index_table->segments->len);
2230 for (i = 0; i < index_table->segments->len; i++) {
2231 MXFIndexTableSegment *cand =
2232 &g_array_index (index_table->segments, MXFIndexTableSegment, i);
2233 if (position >= cand->index_start_position && (cand->index_duration == 0
2235 (cand->index_start_position + cand->index_duration))) {
2236 GST_DEBUG_OBJECT (demux,
2237 "Entry is in Segment #%d , start: %" G_GINT64_FORMAT " , duration: %"
2238 G_GINT64_FORMAT, i, cand->index_start_position, cand->index_duration);
2244 GST_DEBUG_OBJECT (demux,
2245 "Didn't find index table segment for position %" G_GINT64_FORMAT,
2250 /* Were we asked for a keyframe ? */
2252 if (segment->edit_unit_byte_count && !segment->n_index_entries) {
2253 GST_LOG_OBJECT (demux,
2254 "Index table without entries, directly using requested position for keyframe search");
2257 GST_LOG_OBJECT (demux, "keyframe search");
2258 /* Search backwards for keyframe */
2259 for (candidate = position; candidate >= segment->index_start_position;
2261 MXFIndexEntry *segment_index_entry =
2262 &segment->index_entries[candidate - segment->index_start_position];
2265 if (segment_index_entry->flags & 0x80) {
2266 GST_LOG_OBJECT (demux, "Found keyframe at position %" G_GINT64_FORMAT,
2268 position = candidate;
2272 /* If a keyframe offset is specified and valid, use that */
2273 if (segment_index_entry->key_frame_offset
2274 && !(segment_index_entry->flags & 0x08)) {
2275 GST_DEBUG_OBJECT (demux, "Using keyframe offset %d",
2276 segment_index_entry->key_frame_offset);
2277 position = candidate + segment_index_entry->key_frame_offset;
2278 if (position < segment->index_start_position) {
2279 GST_DEBUG_OBJECT (demux, "keyframe info is in previous segment");
2280 goto search_in_segment;
2285 /* If we reached the beginning, use that */
2286 if (candidate == 0) {
2287 GST_LOG_OBJECT (demux,
2288 "Reached position 0 while searching for keyframe");
2293 /* If we looped past the beginning of this segment, go to the previous one */
2294 if (candidate == segment->index_start_position) {
2295 position = candidate - 1;
2296 GST_LOG_OBJECT (demux, "Looping with new position %" G_GINT64_FORMAT,
2298 goto search_in_segment;
2301 /* loop back to check previous entry */
2306 /* Figure out the stream offset (also called "body offset" in specification) */
2307 if (segment->edit_unit_byte_count && !segment->n_index_entries) {
2308 /* Constant entry table. */
2309 stream_offset = position * segment->edit_unit_byte_count;
2310 if (etrack->delta_id >= 0) {
2311 MXFDeltaEntry *delta_entry = &segment->delta_entries[etrack->delta_id];
2312 GST_LOG_OBJECT (demux,
2313 "Using delta %d pos_table_index:%d slice:%u element_delta:%u",
2314 etrack->delta_id, delta_entry->pos_table_index, delta_entry->slice,
2315 delta_entry->element_delta);
2316 stream_offset += delta_entry->element_delta;
2317 } else if (etrack->min_edit_units != 1) {
2318 GST_LOG_OBJECT (demux, "Handling minimum edit unit %u",
2319 etrack->min_edit_units);
2321 MIN (etrack->min_edit_units,
2322 (segment->index_start_position + segment->index_duration) - position);
2323 entry->size = segment->edit_unit_byte_count * entry->duration;
2325 entry->size = segment->edit_unit_byte_count;
2327 } else if (segment->n_index_entries) {
2328 MXFIndexEntry *segment_index_entry;
2329 MXFDeltaEntry *delta_entry = NULL;
2330 g_assert (position <=
2331 segment->index_start_position + segment->n_index_entries);
2332 segment_index_entry =
2333 &segment->index_entries[position - segment->index_start_position];
2334 stream_offset = segment_index_entry->stream_offset;
2336 if (segment->n_delta_entries > 0)
2337 delta_entry = &segment->delta_entries[etrack->delta_id];
2340 GST_LOG_OBJECT (demux,
2341 "Using delta %d pos_table_index:%d slice:%u element_delta:%u",
2342 etrack->delta_id, delta_entry->pos_table_index, delta_entry->slice,
2343 delta_entry->element_delta);
2345 /* Apply offset from slice/delta if needed */
2346 if (delta_entry->slice)
2348 segment_index_entry->slice_offset[delta_entry->slice - 1];
2349 stream_offset += delta_entry->element_delta;
2350 if (delta_entry->pos_table_index == -1) {
2351 entry->keyframe = (segment_index_entry->flags & 0x80) == 0x80;
2353 /* FIXME : Handle fractional offset position (delta_entry->pos_table_offset > 0) */
2356 /* Apply reverse temporal reordering if present */
2357 if (index_table->reordered_delta_entry == etrack->delta_id) {
2358 if (position >= index_table->reverse_temporal_offsets->len) {
2359 GST_WARNING_OBJECT (demux,
2360 "Can't apply temporal offset for position %" G_GINT64_FORMAT
2361 " (max:%d)", position, index_table->reverse_temporal_offsets->len);
2363 if (demux->temporal_order_misuse) {
2364 GST_DEBUG_OBJECT (demux, "Handling temporal order misuse");
2365 entry->pts = position + segment_index_entry->temporal_offset;
2368 position + g_array_index (index_table->reverse_temporal_offsets,
2370 GST_LOG_OBJECT (demux,
2371 "Applied temporal offset. dts:%" G_GINT64_FORMAT " pts:%"
2372 G_GINT64_FORMAT, position, entry->pts);
2375 entry->pts = position;
2377 /* Note : This should have been handled in the parser */
2378 GST_WARNING_OBJECT (demux,
2379 "Can't handle index tables without entries nor constant edit unit byte count");
2383 /* Find the partition containing the stream offset for this track */
2385 get_partition_for_stream_offset (demux, etrack, stream_offset);
2387 if (!offset_partition) {
2388 GST_WARNING_OBJECT (demux,
2389 "Couldn't find matching partition for stream offset %" G_GUINT64_FORMAT,
2393 GST_DEBUG_OBJECT (demux, "Entry is in partition %" G_GUINT64_FORMAT,
2394 offset_partition->partition.this_partition);
2397 /* Convert stream offset to absolute offset using matching partition */
2399 offset_partition->partition.this_partition +
2400 offset_partition->essence_container_offset + (stream_offset -
2401 offset_partition->partition.body_offset);
2403 GST_LOG_OBJECT (demux,
2404 "track %d position:%" G_GINT64_FORMAT " stream_offset %" G_GUINT64_FORMAT
2405 " matches to absolute offset %" G_GUINT64_FORMAT, etrack->track_id,
2406 position, stream_offset, absolute_offset);
2407 entry->initialized = TRUE;
2408 entry->offset = absolute_offset;
2409 entry->dts = position;
2415 * find_entry_for_offset:
2416 * @demux: The demuxer
2417 * @etrack: The target essence track
2418 * @offset: An absolute byte offset (excluding run_in)
2419 * @entry: (out): Will be filled with the matching entry information
2421 * Find the entry located at the given absolute byte offset.
2423 * Note: the offset requested should be in the current partition !
2425 * Returns: TRUE if the entry was found and @entry was properly filled, else
2429 find_entry_for_offset (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack,
2430 guint64 offset, GstMXFDemuxIndex * retentry)
2432 GstMXFDemuxIndexTable *index_table = get_track_index_table (demux, etrack);
2434 MXFIndexTableSegment *index_segment = NULL;
2435 GstMXFDemuxPartition *partition = demux->current_partition;
2436 guint64 original_offset = offset;
2437 guint64 cp_offset = 0; /* Offset in Content Package */
2438 MXFIndexEntry *index_entry = NULL;
2439 MXFDeltaEntry *delta_entry = NULL;
2440 gint64 position = 0;
2442 GST_DEBUG_OBJECT (demux,
2443 "track %d body_sid:%d index_sid:%d offset:%" G_GUINT64_FORMAT,
2444 etrack->track_id, etrack->body_sid, etrack->index_sid, offset);
2447 retentry->duration = 1;
2448 retentry->keyframe = TRUE;
2450 /* Index-less search */
2451 if (etrack->offsets) {
2452 for (i = 0; i < etrack->offsets->len; i++) {
2453 GstMXFDemuxIndex *idx =
2454 &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
2456 if (idx->initialized && idx->offset != 0 && idx->offset == offset) {
2458 GST_DEBUG_OBJECT (demux,
2459 "Found in track index. Position:%" G_GINT64_FORMAT, idx->dts);
2465 /* Actual index search */
2466 if (!index_table || !index_table->segments->len) {
2467 GST_WARNING_OBJECT (demux, "No index table or entries to search in");
2472 GST_WARNING_OBJECT (demux, "No current partition for search");
2476 /* Searching for a stream position from an absolute offset works in 3 steps:
2478 * 1. Convert the absolute offset to a "stream offset" based on the partition
2480 * 2. Find the segment for that "stream offset"
2481 * 3. Match the entry within that segment
2484 /* Convert to stream offset */
2485 GST_LOG_OBJECT (demux,
2486 "offset %" G_GUINT64_FORMAT " this_partition:%" G_GUINT64_FORMAT
2487 " essence_container_offset:%" G_GINT64_FORMAT " partition body offset %"
2488 G_GINT64_FORMAT, offset, partition->partition.this_partition,
2489 partition->essence_container_offset, partition->partition.body_offset);
2491 offset - partition->partition.this_partition -
2492 partition->essence_container_offset + partition->partition.body_offset;
2494 GST_LOG_OBJECT (demux, "stream offset %" G_GUINT64_FORMAT, offset);
2496 /* Find the segment that covers the given stream offset (the highest one that
2497 * covers that offset) */
2498 for (i = index_table->segments->len - 1; i >= 0; i--) {
2500 &g_array_index (index_table->segments, MXFIndexTableSegment, i);
2501 GST_DEBUG_OBJECT (demux,
2502 "Checking segment #%d (essence_offset %" G_GUINT64_FORMAT ")", i,
2503 index_segment->segment_start_offset);
2504 /* Not in the right segment yet */
2505 if (offset >= index_segment->segment_start_offset) {
2506 GST_LOG_OBJECT (demux, "Found");
2510 if (!index_segment) {
2511 GST_WARNING_OBJECT (demux,
2512 "Couldn't find index table segment for given offset");
2516 /* In the right segment, figure out:
2517 * * the offset in the content package,
2518 * * the position in edit units
2519 * * the matching entry (if the table has entries)
2521 if (index_segment->edit_unit_byte_count) {
2522 cp_offset = offset % index_segment->edit_unit_byte_count;
2523 position = offset / index_segment->edit_unit_byte_count;
2524 /* Boundary check */
2525 if ((position < index_segment->index_start_position)
2526 || (index_segment->index_duration
2528 (index_segment->index_start_position +
2529 index_segment->index_duration))) {
2530 GST_WARNING_OBJECT (demux,
2531 "Invalid offset, exceeds table segment limits");
2534 if (etrack->min_edit_units != 1) {
2535 retentry->duration = MIN (etrack->min_edit_units,
2536 (index_segment->index_start_position +
2537 index_segment->index_duration) - position);
2538 retentry->size = index_segment->edit_unit_byte_count * retentry->duration;
2540 retentry->size = index_segment->edit_unit_byte_count;
2543 /* Find the content package entry containing this offset */
2545 for (cpidx = 0; cpidx < index_segment->n_index_entries; cpidx++) {
2546 index_entry = &index_segment->index_entries[cpidx];
2547 GST_DEBUG_OBJECT (demux,
2548 "entry #%u offset:%" G_GUINT64_FORMAT " stream_offset:%"
2549 G_GUINT64_FORMAT, cpidx, offset, index_entry->stream_offset);
2550 if (index_entry->stream_offset == offset) {
2551 index_entry = &index_segment->index_entries[cpidx];
2552 /* exactly on the entry */
2553 cp_offset = offset - index_entry->stream_offset;
2554 position = index_segment->index_start_position + cpidx;
2557 if (index_entry->stream_offset > offset && cpidx > 0) {
2558 index_entry = &index_segment->index_entries[cpidx - 1];
2559 /* One too far, result is in previous entry */
2560 cp_offset = offset - index_entry->stream_offset;
2561 position = index_segment->index_start_position + cpidx - 1;
2565 if (cpidx == index_segment->n_index_entries) {
2566 GST_WARNING_OBJECT (demux,
2567 "offset exceeds maximum number of entries in table segment");
2572 /* If the track comes from an interleaved essence container and doesn't have a
2573 * delta_id set, figure it out now */
2574 if (G_UNLIKELY (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN)) {
2576 GST_DEBUG_OBJECT (demux,
2577 "Unknown delta_id for track. Attempting to resolve it");
2579 if (index_segment->n_delta_entries == 0) {
2580 /* No delta entries, nothing we can do about this */
2581 GST_DEBUG_OBJECT (demux, "Index table has no delta entries, ignoring");
2582 etrack->delta_id = MXF_INDEX_DELTA_ID_IGNORE;
2583 } else if (!index_entry) {
2584 for (delta = 0; delta < index_segment->n_delta_entries; delta++) {
2585 /* No entry, therefore no slices */
2586 GST_LOG_OBJECT (demux,
2587 "delta #%d offset %" G_GUINT64_FORMAT " cp_offs:%" G_GUINT64_FORMAT
2588 " element_delta:%u", delta, offset, cp_offset,
2589 index_segment->delta_entries[delta].element_delta);
2590 if (cp_offset == index_segment->delta_entries[delta].element_delta) {
2591 GST_DEBUG_OBJECT (demux, "Matched to delta %d", delta);
2592 etrack->delta_id = delta;
2593 delta_entry = &index_segment->delta_entries[delta];
2598 for (delta = 0; delta < index_segment->n_delta_entries; delta++) {
2599 guint64 delta_offs = 0;
2600 /* If we are not in the first slice, take that offset into account */
2601 if (index_segment->delta_entries[delta].slice)
2603 index_entry->slice_offset[index_segment->
2604 delta_entries[delta].slice - 1];
2605 /* Add the offset for this delta */
2606 delta_offs += index_segment->delta_entries[delta].element_delta;
2607 if (cp_offset == delta_offs) {
2608 GST_DEBUG_OBJECT (demux, "Matched to delta %d", delta);
2609 etrack->delta_id = delta;
2610 delta_entry = &index_segment->delta_entries[delta];
2616 /* If we didn't managed to match, ignore it from now on */
2617 if (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN) {
2618 GST_WARNING_OBJECT (demux,
2619 "Couldn't match delta id, ignoring it from now on");
2620 etrack->delta_id = MXF_INDEX_DELTA_ID_IGNORE;
2622 } else if (index_segment->n_delta_entries > 0) {
2623 delta_entry = &index_segment->delta_entries[etrack->delta_id];
2626 if (index_entry && delta_entry && delta_entry->pos_table_index == -1) {
2627 retentry->keyframe = (index_entry->flags & 0x80) == 0x80;
2628 if (!demux->temporal_order_misuse)
2630 position + g_array_index (index_table->reverse_temporal_offsets,
2633 retentry->pts = position + index_entry->temporal_offset;
2634 GST_LOG_OBJECT (demux,
2635 "Applied temporal offset. dts:%" G_GINT64_FORMAT " pts:%"
2636 G_GINT64_FORMAT, position, retentry->pts);
2638 retentry->pts = position;
2640 /* FIXME : check if position and cp_offs matches the table */
2641 GST_LOG_OBJECT (demux, "Found in index table. position:%" G_GINT64_FORMAT,
2643 retentry->initialized = TRUE;
2644 retentry->offset = original_offset;
2645 retentry->dts = position;
2650 static GstFlowReturn
2651 gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
2652 GstMXFKLV * klv, gboolean peek)
2654 GstFlowReturn ret = GST_FLOW_OK;
2655 guint32 track_number;
2657 GstBuffer *inbuf = NULL;
2658 GstBuffer *outbuf = NULL;
2659 GstMXFDemuxEssenceTrack *etrack = NULL;
2660 /* As in GstMXFDemuxIndex */
2661 guint64 pts = G_MAXUINT64;
2662 gint32 max_temporal_offset = 0;
2663 GstMXFDemuxIndex index_entry = { 0, };
2666 GST_DEBUG_OBJECT (demux,
2667 "Handling generic container essence element of size %" G_GSIZE_FORMAT
2668 " at offset %" G_GUINT64_FORMAT, klv->length,
2669 klv->offset + klv->consumed);
2671 GST_DEBUG_OBJECT (demux, " type = 0x%02x", klv->key.u[12]);
2672 GST_DEBUG_OBJECT (demux, " essence element count = 0x%02x", klv->key.u[13]);
2673 GST_DEBUG_OBJECT (demux, " essence element type = 0x%02x", klv->key.u[14]);
2674 GST_DEBUG_OBJECT (demux, " essence element number = 0x%02x", klv->key.u[15]);
2676 if (demux->current_partition->essence_container_offset == 0) {
2677 demux->current_partition->essence_container_offset =
2678 demux->offset - demux->current_partition->partition.this_partition -
2680 if (demux->current_partition->single_track
2681 && demux->current_partition->single_track->wrapping !=
2682 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2683 demux->current_partition->essence_container_offset += klv->data_offset;
2684 demux->current_partition->clip_klv = *klv;
2685 /* "consume" the initial bytes of the KLV */
2686 klv->consumed = klv->data_offset;
2687 GST_DEBUG_OBJECT (demux,
2688 "Non-frame wrapping, updated essence_container_offset to %"
2689 G_GUINT64_FORMAT, demux->current_partition->essence_container_offset);
2693 if (!demux->current_package) {
2694 GST_ERROR_OBJECT (demux, "No package selected yet");
2695 return GST_FLOW_ERROR;
2698 if (demux->src->len == 0) {
2699 GST_ERROR_OBJECT (demux, "No streams created yet");
2700 return GST_FLOW_ERROR;
2703 if (demux->essence_tracks->len == 0) {
2704 GST_ERROR_OBJECT (demux, "No essence streams found in the metadata");
2705 return GST_FLOW_ERROR;
2708 /* Identify and fetch the essence track */
2709 track_number = GST_READ_UINT32_BE (&klv->key.u[12]);
2711 etrack = demux->current_partition->single_track;
2713 for (i = 0; i < demux->essence_tracks->len; i++) {
2714 GstMXFDemuxEssenceTrack *tmp =
2715 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
2717 if (tmp->body_sid == demux->current_partition->partition.body_sid &&
2718 (tmp->track_number == track_number || tmp->track_number == 0)) {
2725 GST_DEBUG_OBJECT (demux,
2726 "No essence track for this essence element found");
2731 GST_DEBUG_OBJECT (demux,
2732 "Handling generic container essence (track %d , position:%"
2733 G_GINT64_FORMAT ", number: 0x%08x , frame-wrapped:%d)", etrack->track_id,
2734 etrack->position, track_number,
2735 etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
2737 /* Fetch the current entry.
2739 * 1. If we don't have a current position, use find_entry_for_offset()
2740 * 2. If we do have a position, use find_edit_entry()
2742 * 3. If we are dealing with frame-wrapped content, pull the corresponding
2743 * data from upstream (because it wasn't provided). If we didn't find an
2744 * entry, error out because we can't deal with a frame-wrapped stream
2748 offset = klv->offset + klv->consumed;
2750 /* Update the track position (in case of resyncs) */
2751 if (etrack->position == -1) {
2752 GST_DEBUG_OBJECT (demux,
2753 "Unknown essence track position, looking into index");
2754 if (!find_entry_for_offset (demux, etrack, offset - demux->run_in,
2756 GST_WARNING_OBJECT (demux, "Essence track position not in index");
2759 /* Update track position */
2760 etrack->position = index_entry.dts;
2761 } else if (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN) {
2762 GST_DEBUG_OBJECT (demux,
2763 "Unknown essence track delta_id, looking into index");
2764 if (!find_entry_for_offset (demux, etrack, offset - demux->run_in,
2766 /* Non-fatal, fallback to legacy mode */
2767 GST_WARNING_OBJECT (demux, "Essence track position not in index");
2768 } else if (etrack->position != index_entry.dts) {
2769 GST_ERROR_OBJECT (demux,
2770 "track position doesn't match %" G_GINT64_FORMAT " entry dts %"
2771 G_GINT64_FORMAT, etrack->position, index_entry.dts);
2772 return GST_FLOW_ERROR;
2775 if (!find_edit_entry (demux, etrack, etrack->position, FALSE, &index_entry)) {
2776 GST_DEBUG_OBJECT (demux, "Couldn't find entry");
2777 } else if (etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2778 if (etrack->delta_id != MXF_INDEX_DELTA_ID_IGNORE
2779 && index_entry.offset != offset) {
2780 GST_ERROR_OBJECT (demux,
2781 "demux offset doesn't match %" G_GINT64_FORMAT " entry offset %"
2782 G_GUINT64_FORMAT, offset, index_entry.offset);
2783 return GST_FLOW_ERROR;
2785 } else if (index_entry.offset != klv->offset + klv->consumed &&
2786 index_entry.offset != klv->offset + klv->data_offset) {
2787 GST_ERROR_OBJECT (demux,
2788 "KLV offset doesn't match %" G_GINT64_FORMAT " entry offset %"
2789 G_GUINT64_FORMAT, klv->offset + klv->consumed, index_entry.offset);
2790 return GST_FLOW_ERROR;
2794 if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2795 /* We need entry information to deal with non-frame-wrapped content */
2796 if (!index_entry.initialized) {
2797 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2798 ("Essence with non-frame-wrapping require an index table to be present"));
2799 return GST_FLOW_ERROR;
2801 /* We cannot deal with non-frame-wrapping in push mode for now */
2802 if (!demux->random_access) {
2803 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2804 ("Non-frame-wrapping is not support in push mode"));
2805 return GST_FLOW_ERROR;
2809 /* FIXME : If we're peeking and don't need to actually parse the data, we
2810 * should avoid pulling the content from upstream */
2811 if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2812 g_assert (index_entry.size);
2813 GST_DEBUG_OBJECT (demux, "Should only grab %" G_GUINT64_FORMAT " bytes",
2816 gst_mxf_demux_pull_range (demux, index_entry.offset, index_entry.size,
2818 if (ret != GST_FLOW_OK)
2820 if (klv->consumed == 0)
2821 klv->consumed = klv->data_offset + index_entry.size;
2823 klv->consumed += index_entry.size;
2824 if (klv != &demux->current_partition->clip_klv)
2825 demux->current_partition->clip_klv = *klv;
2826 GST_LOG_OBJECT (demux,
2827 "klv data_offset:%" G_GUINT64_FORMAT " length:%" G_GSIZE_FORMAT
2828 " consumed:%" G_GUINT64_FORMAT, klv->data_offset, klv->length,
2830 /* Switch back to KLV mode if we're done with this one */
2831 if (klv->length + klv->data_offset == klv->consumed)
2832 demux->state = GST_MXF_DEMUX_STATE_KLV;
2834 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
2837 ret = gst_mxf_demux_fill_klv (demux, klv);
2838 if (ret != GST_FLOW_OK)
2841 /* Create subbuffer to be able to change metadata */
2843 gst_buffer_copy_region (klv->data, GST_BUFFER_COPY_ALL, 0,
2844 gst_buffer_get_size (klv->data));
2848 if (index_entry.initialized) {
2849 GST_DEBUG_OBJECT (demux, "Got entry dts:%" G_GINT64_FORMAT " keyframe:%d",
2850 index_entry.dts, index_entry.keyframe);
2852 if (index_entry.initialized && !index_entry.keyframe)
2853 GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT);
2855 if (etrack->handle_func) {
2856 /* Takes ownership of inbuf */
2858 etrack->handle_func (&klv->key, inbuf, etrack->caps,
2859 etrack->source_track, etrack->mapping_data, &outbuf);
2867 if (ret != GST_FLOW_OK) {
2868 GST_ERROR_OBJECT (demux, "Failed to handle essence element");
2870 gst_buffer_unref (outbuf);
2876 if (!index_entry.initialized) {
2877 /* This can happen when doing scanning without entry tables */
2878 index_entry.duration = 1;
2879 index_entry.offset = demux->offset - demux->run_in;
2880 index_entry.dts = etrack->position;
2881 index_entry.pts = etrack->intra_only ? etrack->position : G_MAXUINT64;
2882 index_entry.keyframe =
2883 !GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
2884 index_entry.initialized = TRUE;
2885 GST_DEBUG_OBJECT (demux,
2886 "Storing newly discovered information on track %d. dts: %"
2887 G_GINT64_FORMAT " offset:%" G_GUINT64_FORMAT " keyframe:%d",
2888 etrack->track_id, index_entry.dts, index_entry.offset,
2889 index_entry.keyframe);
2891 if (!etrack->offsets)
2892 etrack->offsets = g_array_new (FALSE, TRUE, sizeof (GstMXFDemuxIndex));
2894 /* We only ever append to the track offset entry. */
2895 g_assert (etrack->position <= etrack->offsets->len);
2896 g_array_insert_val (etrack->offsets, etrack->position, index_entry);
2903 GST_DEBUG_OBJECT (demux, "No output buffer created");
2910 max_temporal_offset = get_track_max_temporal_offset (demux, etrack);
2912 for (i = 0; i < demux->src->len; i++) {
2913 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
2915 if (pad->current_essence_track != etrack)
2919 GST_DEBUG_OBJECT (pad, "Pad is already EOS");
2923 if (etrack->position < pad->current_essence_track_position) {
2924 GST_DEBUG_OBJECT (pad,
2925 "Not at current component's position (track:%" G_GINT64_FORMAT
2926 " essence:%" G_GINT64_FORMAT ")", etrack->position,
2927 pad->current_essence_track_position);
2932 GstMXFDemuxPad *earliest = gst_mxf_demux_get_earliest_pad (demux);
2934 if (earliest && earliest != pad && earliest->position < pad->position &&
2935 pad->position - earliest->position > demux->max_drift) {
2936 GST_DEBUG_OBJECT (earliest,
2937 "Pad is too far ahead of time (%" GST_TIME_FORMAT " vs earliest:%"
2938 GST_TIME_FORMAT ")", GST_TIME_ARGS (earliest->position),
2939 GST_TIME_ARGS (pad->position));
2944 /* Create another subbuffer to have writable metadata */
2946 gst_buffer_copy_region (inbuf, GST_BUFFER_COPY_ALL, 0,
2947 gst_buffer_get_size (inbuf));
2949 pts = index_entry.pts;
2951 GST_BUFFER_DTS (outbuf) = pad->position;
2952 if (etrack->intra_only) {
2953 GST_BUFFER_PTS (outbuf) = pad->position;
2954 } else if (pts != G_MAXUINT64) {
2955 GST_BUFFER_PTS (outbuf) = gst_util_uint64_scale (pts * GST_SECOND,
2956 pad->current_essence_track->source_track->edit_rate.d,
2957 pad->current_essence_track->source_track->edit_rate.n);
2958 GST_BUFFER_PTS (outbuf) +=
2959 gst_util_uint64_scale (pad->current_component_start_position *
2960 GST_SECOND, pad->material_track->edit_rate.d,
2961 pad->material_track->edit_rate.n);
2962 /* We are dealing with reordered data, the PTS is shifted forward by the
2963 * maximum temporal reordering (the DTS remain as-is). */
2964 if (max_temporal_offset > 0)
2965 GST_BUFFER_PTS (outbuf) +=
2966 gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
2967 pad->current_essence_track->source_track->edit_rate.d,
2968 pad->current_essence_track->source_track->edit_rate.n);
2971 GST_BUFFER_PTS (outbuf) = GST_CLOCK_TIME_NONE;
2974 GST_BUFFER_DURATION (outbuf) =
2975 gst_util_uint64_scale (GST_SECOND,
2976 index_entry.duration *
2977 pad->current_essence_track->source_track->edit_rate.d,
2978 pad->current_essence_track->source_track->edit_rate.n);
2979 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
2980 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
2982 if (pad->material_track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE
2983 && pad->start_timecode.config.fps_n != 0
2984 && pad->start_timecode.config.fps_d != 0) {
2985 if (etrack->intra_only) {
2986 GstVideoTimeCode timecode = pad->start_timecode;
2988 gst_video_time_code_add_frames (&timecode,
2989 pad->current_material_track_position);
2990 gst_buffer_add_video_time_code_meta (outbuf, &timecode);
2991 } else if (pts != G_MAXUINT64) {
2992 GstVideoTimeCode timecode = pad->start_timecode;
2994 gst_video_time_code_add_frames (&timecode,
2995 pad->current_component_start_position);
2996 gst_video_time_code_add_frames (&timecode,
2997 gst_util_uint64_scale (pts,
2998 pad->material_track->edit_rate.n *
2999 pad->current_essence_track->source_track->edit_rate.d,
3000 pad->material_track->edit_rate.d *
3001 pad->current_essence_track->source_track->edit_rate.n));
3002 gst_buffer_add_video_time_code_meta (outbuf, &timecode);
3007 /* Update accumulated error and compensate */
3010 (GST_SECOND * pad->current_essence_track->source_track->edit_rate.d) %
3011 pad->current_essence_track->source_track->edit_rate.n;
3012 pad->position_accumulated_error +=
3013 ((gdouble) abs_error) /
3014 ((gdouble) pad->current_essence_track->source_track->edit_rate.n);
3016 if (pad->position_accumulated_error >= 1.0) {
3017 GST_BUFFER_DURATION (outbuf) += 1;
3018 pad->position_accumulated_error -= 1.0;
3021 if (pad->need_segment) {
3024 if (demux->close_seg_event)
3025 gst_pad_push_event (GST_PAD_CAST (pad),
3026 gst_event_ref (demux->close_seg_event));
3028 if (max_temporal_offset > 0) {
3029 GstSegment shift_segment;
3030 /* Handle maximum temporal offset. We are shifting all output PTS for
3031 * this stream by the greatest temporal reordering that can occur. In
3032 * order not to change the stream/running time we shift the segment
3033 * start and stop values accordingly */
3034 gst_segment_copy_into (&demux->segment, &shift_segment);
3035 if (GST_CLOCK_TIME_IS_VALID (shift_segment.start))
3036 shift_segment.start +=
3037 gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
3038 pad->current_essence_track->source_track->edit_rate.d,
3039 pad->current_essence_track->source_track->edit_rate.n);
3040 if (GST_CLOCK_TIME_IS_VALID (shift_segment.stop))
3041 shift_segment.stop +=
3042 gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
3043 pad->current_essence_track->source_track->edit_rate.d,
3044 pad->current_essence_track->source_track->edit_rate.n);
3045 e = gst_event_new_segment (&shift_segment);
3047 e = gst_event_new_segment (&demux->segment);
3048 GST_DEBUG_OBJECT (pad, "Sending segment %" GST_PTR_FORMAT, e);
3049 gst_event_set_seqnum (e, demux->seqnum);
3050 gst_pad_push_event (GST_PAD_CAST (pad), e);
3051 pad->need_segment = FALSE;
3055 gst_pad_push_event (GST_PAD_CAST (pad), gst_event_new_tag (pad->tags));
3059 pad->position += GST_BUFFER_DURATION (outbuf);
3060 pad->current_material_track_position += index_entry.duration;
3063 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
3064 pad->discont = FALSE;
3067 /* Handlers can provide empty GAP buffers to indicate that the parsed
3068 * content was valid but that nothing meaningful needs to be outputted. In
3069 * such cases we send out a GAP event instead */
3070 if (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP) &&
3071 gst_buffer_get_size (outbuf) == 0) {
3072 GstEvent *gap = gst_event_new_gap (GST_BUFFER_DTS (outbuf),
3073 GST_BUFFER_DURATION (outbuf));
3074 gst_buffer_unref (outbuf);
3075 GST_DEBUG_OBJECT (pad,
3076 "Replacing empty gap buffer with gap event %" GST_PTR_FORMAT, gap);
3077 gst_pad_push_event (GST_PAD_CAST (pad), gap);
3079 GST_DEBUG_OBJECT (pad,
3080 "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u: pts %"
3081 GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT
3082 " position %" G_GUINT64_FORMAT, gst_buffer_get_size (outbuf),
3083 pad->material_track->parent.track_id,
3084 GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
3085 GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
3086 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
3087 pad->current_essence_track_position);
3089 ret = gst_pad_push (GST_PAD_CAST (pad), outbuf);
3092 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
3093 GST_LOG_OBJECT (pad, "combined return %s", gst_flow_get_name (ret));
3095 if (pad->position > demux->segment.position)
3096 demux->segment.position = pad->position;
3098 if (ret != GST_FLOW_OK)
3101 pad->current_essence_track_position += index_entry.duration;
3103 if (pad->current_component) {
3104 if (pad->current_component_duration > 0 &&
3105 pad->current_essence_track_position - pad->current_component_start
3106 >= pad->current_component_duration) {
3107 GST_DEBUG_OBJECT (demux, "Switching to next component");
3110 gst_mxf_demux_pad_set_component (demux, pad,
3111 pad->current_component_index + 1);
3112 if (ret == GST_FLOW_OK) {
3113 pad->current_essence_track->position =
3114 pad->current_essence_track_position;
3115 } else if (ret != GST_FLOW_EOS) {
3116 GST_ERROR_OBJECT (demux, "Switching component failed");
3118 } else if (etrack->duration > 0
3119 && pad->current_essence_track_position >= etrack->duration) {
3120 GST_DEBUG_OBJECT (demux,
3121 "Current component position after end of essence track");
3124 } else if (etrack->duration > 0
3125 && pad->current_essence_track_position == etrack->duration) {
3126 GST_DEBUG_OBJECT (demux, "At the end of the essence track");
3130 if (ret == GST_FLOW_EOS) {
3133 GST_DEBUG_OBJECT (pad, "EOS for track");
3135 e = gst_event_new_eos ();
3136 gst_event_set_seqnum (e, demux->seqnum);
3137 gst_pad_push_event (GST_PAD_CAST (pad), e);
3141 if (ret != GST_FLOW_OK)
3147 gst_buffer_unref (inbuf);
3150 gst_buffer_unref (outbuf);
3152 etrack->position += index_entry.duration;
3158 * Called when analyzing the (RIP) Random Index Pack.
3160 * FIXME : If a file doesn't have a RIP, we should iterate the partition headers
3161 * to collect as much information as possible.
3163 * This function collects as much information as possible from the partition headers:
3164 * * Store partition information in the list of partitions
3165 * * Handle any index table segment present
3168 read_partition_header (GstMXFDemux * demux)
3172 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv) != GST_FLOW_OK
3173 || !mxf_is_partition_pack (&klv.key)) {
3177 if (gst_mxf_demux_handle_partition_pack (demux, &klv) != GST_FLOW_OK) {
3179 gst_buffer_unref (klv.data);
3182 gst_mxf_demux_consume_klv (demux, &klv);
3184 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv) != GST_FLOW_OK)
3187 while (mxf_is_fill (&klv.key)) {
3188 gst_mxf_demux_consume_klv (demux, &klv);
3189 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3190 &klv) != GST_FLOW_OK)
3194 if (!mxf_is_index_table_segment (&klv.key)
3195 && demux->current_partition->partition.header_byte_count) {
3196 demux->offset += demux->current_partition->partition.header_byte_count;
3197 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3198 &klv) != GST_FLOW_OK)
3202 while (mxf_is_fill (&klv.key)) {
3203 gst_mxf_demux_consume_klv (demux, &klv);
3204 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3205 &klv) != GST_FLOW_OK)
3209 if (demux->current_partition->partition.index_byte_count
3210 && mxf_is_index_table_segment (&klv.key)) {
3211 guint64 index_end_offset =
3212 demux->offset + demux->current_partition->partition.index_byte_count;
3214 while (demux->offset < index_end_offset) {
3215 if (mxf_is_index_table_segment (&klv.key))
3216 gst_mxf_demux_handle_index_table_segment (demux, &klv);
3217 gst_mxf_demux_consume_klv (demux, &klv);
3219 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3220 &klv) != GST_FLOW_OK)
3225 while (mxf_is_fill (&klv.key)) {
3226 gst_mxf_demux_consume_klv (demux, &klv);
3227 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3228 &klv) != GST_FLOW_OK)
3232 if (mxf_is_generic_container_system_item (&klv.key) ||
3233 mxf_is_generic_container_essence_element (&klv.key) ||
3234 mxf_is_avid_essence_container_essence_element (&klv.key)) {
3235 if (demux->current_partition->essence_container_offset == 0)
3236 demux->current_partition->essence_container_offset =
3237 demux->offset - demux->current_partition->partition.this_partition -
3242 static GstFlowReturn
3243 gst_mxf_demux_handle_random_index_pack (GstMXFDemux * demux, GstMXFKLV * klv)
3249 GstFlowReturn flowret;
3251 GST_DEBUG_OBJECT (demux,
3252 "Handling random index pack of size %" G_GSIZE_FORMAT " at offset %"
3253 G_GUINT64_FORMAT, klv->length, klv->offset);
3255 if (demux->random_index_pack) {
3256 GST_DEBUG_OBJECT (demux, "Already parsed random index pack");
3260 flowret = gst_mxf_demux_fill_klv (demux, klv);
3261 if (flowret != GST_FLOW_OK)
3264 gst_buffer_map (klv->data, &map, GST_MAP_READ);
3266 mxf_random_index_pack_parse (&klv->key, map.data, map.size,
3267 &demux->random_index_pack);
3268 gst_buffer_unmap (klv->data, &map);
3271 GST_ERROR_OBJECT (demux, "Parsing random index pack failed");
3272 return GST_FLOW_ERROR;
3275 for (i = 0; i < demux->random_index_pack->len; i++) {
3276 GstMXFDemuxPartition *p = NULL;
3277 MXFRandomIndexPackEntry *e =
3278 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry, i);
3280 if (e->offset < demux->run_in) {
3281 GST_ERROR_OBJECT (demux, "Invalid random index pack entry");
3282 return GST_FLOW_ERROR;
3285 for (l = demux->partitions; l; l = l->next) {
3286 GstMXFDemuxPartition *tmp = l->data;
3288 if (tmp->partition.this_partition + demux->run_in == e->offset) {
3295 p = g_new0 (GstMXFDemuxPartition, 1);
3296 p->partition.this_partition = e->offset - demux->run_in;
3297 p->partition.body_sid = e->body_sid;
3299 g_list_insert_sorted (demux->partitions, p,
3300 (GCompareFunc) gst_mxf_demux_partition_compare);
3304 for (l = demux->partitions; l; l = l->next) {
3305 GstMXFDemuxPartition *a, *b;
3307 if (l->next == NULL)
3313 b->partition.prev_partition = a->partition.this_partition;
3320 compare_index_table_segment (MXFIndexTableSegment * sa,
3321 MXFIndexTableSegment * sb)
3323 if (sa->body_sid != sb->body_sid)
3324 return (sa->body_sid < sb->body_sid) ? -1 : 1;
3325 if (sa->index_sid != sb->index_sid)
3326 return (sa->index_sid < sb->index_sid) ? -1 : 1;
3327 if (sa->index_start_position != sb->index_start_position)
3328 return (sa->index_start_position < sb->index_start_position) ? -1 : 1;
3330 /* If all the above are equal ... the index table segments are only equal if
3331 * their instance ID are equal. Until March 2022 the FFmpeg MXF muxer would
3332 * write the same instance id for the various (different) index table
3333 * segments, we therefore only check instance ID *after* all the above
3334 * properties to make sure they are really different. */
3335 if (mxf_uuid_is_equal (&sa->instance_id, &sb->instance_id))
3341 static GstFlowReturn
3342 gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux, GstMXFKLV * klv)
3344 MXFIndexTableSegment *segment;
3348 GstFlowReturn flowret;
3350 flowret = gst_mxf_demux_fill_klv (demux, klv);
3351 if (flowret != GST_FLOW_OK)
3354 GST_DEBUG_OBJECT (demux,
3355 "Handling index table segment of size %" G_GSIZE_FORMAT " at offset %"
3356 G_GUINT64_FORMAT, klv->length, klv->offset);
3358 segment = g_new0 (MXFIndexTableSegment, 1);
3360 gst_buffer_map (klv->data, &map, GST_MAP_READ);
3361 ret = mxf_index_table_segment_parse (&klv->key, segment, map.data, map.size);
3362 gst_buffer_unmap (klv->data, &map);
3365 GST_ERROR_OBJECT (demux, "Parsing index table segment failed");
3367 return GST_FLOW_ERROR;
3370 /* Drop it if we already saw it. Ideally we should be able to do this before
3371 parsing (by checking instance UID) */
3372 if (g_list_find_custom (demux->pending_index_table_segments, segment,
3373 (GCompareFunc) compare_index_table_segment)) {
3374 GST_DEBUG_OBJECT (demux, "Already in pending list");
3375 mxf_index_table_segment_reset (segment);
3379 for (tmp = demux->index_tables; tmp; tmp = tmp->next) {
3380 GstMXFDemuxIndexTable *table = (GstMXFDemuxIndexTable *) tmp->data;
3381 if (g_array_binary_search (table->segments, segment,
3382 (GCompareFunc) compare_index_table_segment, NULL)) {
3383 GST_DEBUG_OBJECT (demux, "Already handled");
3384 mxf_index_table_segment_reset (segment);
3390 demux->pending_index_table_segments =
3391 g_list_insert_sorted (demux->pending_index_table_segments, segment,
3392 (GCompareFunc) compare_index_table_segment);
3397 static GstFlowReturn
3398 gst_mxf_demux_peek_klv_packet (GstMXFDemux * demux, guint64 offset,
3401 GstBuffer *buffer = NULL;
3403 GstFlowReturn ret = GST_FLOW_OK;
3405 #ifndef GST_DISABLE_GST_DEBUG
3409 memset (klv, 0, sizeof (GstMXFKLV));
3410 klv->offset = offset;
3412 /* Pull 16 byte key and first byte of BER encoded length */
3414 gst_mxf_demux_pull_range (demux, offset, 17, &buffer)) != GST_FLOW_OK)
3417 gst_buffer_map (buffer, &map, GST_MAP_READ);
3419 memcpy (&klv->key, map.data, 16);
3421 /* Decode BER encoded packet length */
3422 if ((map.data[16] & 0x80) == 0) {
3423 klv->length = map.data[16];
3424 klv->data_offset = 17;
3426 guint slen = map.data[16] & 0x7f;
3428 klv->data_offset = 16 + 1 + slen;
3430 gst_buffer_unmap (buffer, &map);
3431 gst_buffer_unref (buffer);
3434 /* Must be at most 8 according to SMPTE-379M 5.3.4 */
3436 GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
3437 ret = GST_FLOW_ERROR;
3441 /* Now pull the length of the packet */
3442 if ((ret = gst_mxf_demux_pull_range (demux, offset + 17, slen,
3443 &buffer)) != GST_FLOW_OK)
3446 gst_buffer_map (buffer, &map, GST_MAP_READ);
3451 klv->length = (klv->length << 8) | *data;
3457 gst_buffer_unmap (buffer, &map);
3458 gst_buffer_unref (buffer);
3461 /* GStreamer's buffer sizes are stored in a guint so we
3462 * limit ourself to G_MAXUINT large buffers */
3463 if (klv->length > G_MAXUINT) {
3464 GST_ERROR_OBJECT (demux,
3465 "Unsupported KLV packet length: %" G_GSIZE_FORMAT, klv->length);
3466 ret = GST_FLOW_ERROR;
3470 GST_DEBUG_OBJECT (demux,
3471 "Found KLV packet at offset %" G_GUINT64_FORMAT " with key %s and length "
3472 "%" G_GSIZE_FORMAT, offset, mxf_ul_to_string (&klv->key, str),
3477 gst_buffer_unref (buffer);
3482 static GstFlowReturn
3483 gst_mxf_demux_fill_klv (GstMXFDemux * demux, GstMXFKLV * klv)
3487 GST_DEBUG_OBJECT (demux,
3488 "Pulling %" G_GSIZE_FORMAT " bytes from offset %" G_GUINT64_FORMAT,
3489 klv->length, klv->offset + klv->data_offset);
3490 return gst_mxf_demux_pull_range (demux, klv->offset + klv->data_offset,
3491 klv->length, &klv->data);
3494 /* Call when done with a klv. Will release the buffer (if any) and will update
3495 * the demuxer offset position. Do *NOT* call if you do not want the demuxer
3496 * offset to be updated */
3498 gst_mxf_demux_consume_klv (GstMXFDemux * demux, GstMXFKLV * klv)
3501 gst_buffer_unref (klv->data);
3504 GST_DEBUG_OBJECT (demux,
3505 "Consuming KLV offset:%" G_GUINT64_FORMAT " data_offset:%"
3506 G_GUINT64_FORMAT " length:%" G_GSIZE_FORMAT " consumed:%"
3507 G_GUINT64_FORMAT, klv->offset, klv->data_offset, klv->length,
3510 demux->offset = klv->offset + klv->consumed;
3512 demux->offset += klv->data_offset + klv->length;
3516 gst_mxf_demux_pull_random_index_pack (GstMXFDemux * demux)
3519 gint64 filesize = -1;
3520 GstFormat fmt = GST_FORMAT_BYTES;
3522 guint64 old_offset = demux->offset;
3524 GstFlowReturn flow_ret;
3527 if (!gst_pad_peer_query_duration (demux->sinkpad, fmt, &filesize) ||
3528 fmt != GST_FORMAT_BYTES || filesize == -1) {
3529 GST_DEBUG_OBJECT (demux, "Can't query upstream size");
3533 g_assert (filesize > 4);
3536 if (gst_mxf_demux_pull_range (demux, filesize - 4, 4, &buffer) != GST_FLOW_OK) {
3537 GST_DEBUG_OBJECT (demux, "Failed pulling last 4 bytes");
3541 gst_buffer_map (buffer, &map, GST_MAP_READ);
3542 pack_size = GST_READ_UINT32_BE (map.data);
3543 gst_buffer_unmap (buffer, &map);
3545 gst_buffer_unref (buffer);
3547 if (pack_size < 20) {
3548 GST_DEBUG_OBJECT (demux, "Too small pack size (%u bytes)", pack_size);
3550 } else if (pack_size > filesize - 20) {
3551 GST_DEBUG_OBJECT (demux, "Too large pack size (%u bytes)", pack_size);
3555 /* Peek for klv at filesize - pack_size */
3556 if (gst_mxf_demux_peek_klv_packet (demux, filesize - pack_size,
3557 &klv) != GST_FLOW_OK) {
3558 GST_DEBUG_OBJECT (demux, "Failed pulling random index pack key");
3562 if (!mxf_is_random_index_pack (&klv.key)) {
3563 GST_DEBUG_OBJECT (demux, "No random index pack");
3567 demux->offset = filesize - pack_size;
3568 flow_ret = gst_mxf_demux_handle_random_index_pack (demux, &klv);
3570 gst_buffer_unref (klv.data);
3571 demux->offset = old_offset;
3573 if (flow_ret == GST_FLOW_OK && !demux->index_table_segments_collected) {
3574 collect_index_table_segments (demux);
3575 demux->index_table_segments_collected = TRUE;
3580 gst_mxf_demux_parse_footer_metadata (GstMXFDemux * demux)
3582 guint64 old_offset = demux->offset;
3584 GstFlowReturn flow = GST_FLOW_OK;
3585 GstMXFDemuxPartition *old_partition = demux->current_partition;
3587 GST_DEBUG_OBJECT (demux, "Parsing footer metadata");
3589 demux->current_partition = NULL;
3591 gst_mxf_demux_reset_metadata (demux);
3593 if (demux->footer_partition_pack_offset != 0) {
3594 demux->offset = demux->run_in + demux->footer_partition_pack_offset;
3596 MXFRandomIndexPackEntry *entry =
3597 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry,
3598 demux->random_index_pack->len - 1);
3599 demux->offset = entry->offset;
3603 GST_LOG_OBJECT (demux, "Peeking partition pack at offset %" G_GUINT64_FORMAT,
3606 /* Process Partition Pack */
3607 flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3608 if (G_UNLIKELY (flow != GST_FLOW_OK))
3611 if (!mxf_is_partition_pack (&klv.key))
3614 if (gst_mxf_demux_handle_partition_pack (demux, &klv) != GST_FLOW_OK) {
3616 gst_buffer_unref (klv.data);
3620 gst_mxf_demux_consume_klv (demux, &klv);
3622 /* If there's no Header Metadata in this partition, jump to the previous
3624 if (demux->current_partition->partition.header_byte_count == 0) {
3625 /* Reached the first partition, bail out */
3626 if (demux->current_partition->partition.this_partition == 0)
3630 demux->run_in + demux->current_partition->partition.prev_partition;
3634 /* Next up should be an optional fill pack followed by a primer pack */
3636 flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3637 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3638 /* If ever we can't get the next KLV, jump to the previous partition */
3639 if (!demux->current_partition->partition.prev_partition)
3642 demux->run_in + demux->current_partition->partition.prev_partition;
3646 if (mxf_is_fill (&klv.key)) {
3647 gst_mxf_demux_consume_klv (demux, &klv);
3648 } else if (mxf_is_primer_pack (&klv.key)) {
3649 /* Update primer mapping if present (jump to previous if it failed) */
3650 if (!demux->current_partition->primer.mappings) {
3651 if (gst_mxf_demux_handle_primer_pack (demux, &klv) != GST_FLOW_OK) {
3652 gst_mxf_demux_consume_klv (demux, &klv);
3653 if (!demux->current_partition->partition.prev_partition)
3657 demux->current_partition->partition.prev_partition;
3661 gst_mxf_demux_consume_klv (demux, &klv);
3664 if (!demux->current_partition->partition.prev_partition)
3667 demux->run_in + demux->current_partition->partition.prev_partition;
3672 /* parse metadata for this partition */
3673 while (demux->offset <
3674 demux->run_in + demux->current_partition->primer.offset +
3675 demux->current_partition->partition.header_byte_count) {
3676 flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3677 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3678 if (!demux->current_partition->partition.prev_partition)
3681 demux->run_in + demux->current_partition->partition.prev_partition;
3685 if (mxf_is_metadata (&klv.key)) {
3686 flow = gst_mxf_demux_handle_metadata (demux, &klv);
3687 gst_mxf_demux_consume_klv (demux, &klv);
3689 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3690 gst_mxf_demux_reset_metadata (demux);
3691 if (!demux->current_partition->partition.prev_partition)
3694 demux->run_in + demux->current_partition->partition.prev_partition;
3697 } else if (mxf_is_descriptive_metadata (&klv.key)) {
3698 gst_mxf_demux_handle_descriptive_metadata (demux, &klv);
3699 gst_mxf_demux_consume_klv (demux, &klv);
3701 gst_mxf_demux_consume_klv (demux, &klv);
3705 /* resolve references etc */
3706 if (!demux->preface || gst_mxf_demux_resolve_references (demux) !=
3707 GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
3708 /* Don't attempt to parse metadata from this partition again */
3709 demux->current_partition->parsed_metadata = TRUE;
3710 /* Skip to previous partition or bail out */
3711 if (!demux->current_partition->partition.prev_partition)
3714 demux->run_in + demux->current_partition->partition.prev_partition;
3719 demux->offset = old_offset;
3720 demux->current_partition = old_partition;
3723 static GstFlowReturn
3724 gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, GstMXFKLV * klv,
3727 MXFUL *key = &klv->key;
3728 #ifndef GST_DISABLE_GST_DEBUG
3731 GstFlowReturn ret = GST_FLOW_OK;
3733 if (demux->update_metadata
3735 && (demux->offset >=
3736 demux->run_in + demux->current_partition->primer.offset +
3737 demux->current_partition->partition.header_byte_count ||
3738 mxf_is_generic_container_system_item (key) ||
3739 mxf_is_generic_container_essence_element (key) ||
3740 mxf_is_avid_essence_container_essence_element (key))) {
3741 demux->current_partition->parsed_metadata = TRUE;
3742 if ((ret = gst_mxf_demux_resolve_references (demux)) != GST_FLOW_OK ||
3743 (ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
3746 } else if (demux->metadata_resolved && demux->requested_package_string) {
3747 if ((ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
3752 if (!mxf_is_mxf_packet (key)) {
3753 GST_WARNING_OBJECT (demux,
3754 "Skipping non-MXF packet of size %" G_GSIZE_FORMAT " at offset %"
3755 G_GUINT64_FORMAT ", key: %s", klv->length,
3756 demux->offset, mxf_ul_to_string (key, key_str));
3757 } else if (mxf_is_partition_pack (key)) {
3758 ret = gst_mxf_demux_handle_partition_pack (demux, klv);
3759 } else if (mxf_is_primer_pack (key)) {
3760 ret = gst_mxf_demux_handle_primer_pack (demux, klv);
3761 } else if (mxf_is_metadata (key)) {
3762 ret = gst_mxf_demux_handle_metadata (demux, klv);
3763 } else if (mxf_is_descriptive_metadata (key)) {
3764 ret = gst_mxf_demux_handle_descriptive_metadata (demux, klv);
3765 } else if (mxf_is_generic_container_system_item (key)) {
3766 if (demux->pending_index_table_segments)
3767 collect_index_table_segments (demux);
3768 ret = gst_mxf_demux_handle_generic_container_system_item (demux, klv);
3769 } else if (mxf_is_generic_container_essence_element (key) ||
3770 mxf_is_avid_essence_container_essence_element (key)) {
3771 if (demux->pending_index_table_segments)
3772 collect_index_table_segments (demux);
3774 gst_mxf_demux_handle_generic_container_essence_element (demux, klv,
3776 } else if (mxf_is_random_index_pack (key)) {
3777 ret = gst_mxf_demux_handle_random_index_pack (demux, klv);
3779 if (ret == GST_FLOW_OK && demux->random_access
3780 && !demux->index_table_segments_collected) {
3781 collect_index_table_segments (demux);
3782 demux->index_table_segments_collected = TRUE;
3784 } else if (mxf_is_index_table_segment (key)) {
3785 ret = gst_mxf_demux_handle_index_table_segment (demux, klv);
3786 } else if (mxf_is_fill (key)) {
3787 GST_DEBUG_OBJECT (demux,
3788 "Skipping filler packet of size %" G_GSIZE_FORMAT " at offset %"
3789 G_GUINT64_FORMAT, klv->length, demux->offset);
3791 GST_DEBUG_OBJECT (demux,
3792 "Skipping unknown packet of size %" G_GSIZE_FORMAT " at offset %"
3793 G_GUINT64_FORMAT ", key: %s", klv->length,
3794 demux->offset, mxf_ul_to_string (key, key_str));
3802 gst_mxf_demux_set_partition_for_offset (GstMXFDemux * demux, guint64 offset)
3806 GST_LOG_OBJECT (demux, "offset %" G_GUINT64_FORMAT, offset);
3808 /* This partition will already be parsed, otherwise
3809 * the position wouldn't be in the index */
3810 for (l = demux->partitions; l; l = l->next) {
3811 GstMXFDemuxPartition *p = l->data;
3813 if (p->partition.this_partition + demux->run_in <= offset)
3814 demux->current_partition = p;
3816 if (demux->current_partition)
3817 GST_DEBUG_OBJECT (demux,
3818 "Current partition now %p (body_sid:%d index_sid:%d this_partition:%"
3819 G_GUINT64_FORMAT ")", demux->current_partition,
3820 demux->current_partition->partition.body_sid,
3821 demux->current_partition->partition.index_sid,
3822 demux->current_partition->partition.this_partition);
3824 GST_DEBUG_OBJECT (demux, "Haven't found partition for offset yet");
3828 find_closest_offset (GArray * offsets, gint64 * position, gboolean keyframe)
3830 GstMXFDemuxIndex *idx;
3831 gint64 current_position = *position;
3833 if (!offsets || offsets->len == 0)
3836 current_position = MIN (current_position, offsets->len - 1);
3838 idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
3839 while (idx->offset == 0 || (keyframe && !idx->keyframe)) {
3841 if (current_position < 0)
3843 idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
3846 if (idx->offset != 0 && (!keyframe || idx->keyframe)) {
3847 *position = current_position;
3855 gst_mxf_demux_find_essence_element (GstMXFDemux * demux,
3856 GstMXFDemuxEssenceTrack * etrack, gint64 * position, gboolean keyframe)
3858 GstFlowReturn ret = GST_FLOW_OK;
3859 guint64 old_offset = demux->offset;
3860 GstMXFDemuxPartition *old_partition = demux->current_partition;
3863 gint64 requested_position = *position, index_start_position;
3864 GstMXFDemuxIndex index_entry = { 0, };
3866 GST_DEBUG_OBJECT (demux, "Trying to find essence element %" G_GINT64_FORMAT
3867 " of track 0x%08x with body_sid %u (keyframe %d)", *position,
3868 etrack->track_number, etrack->body_sid, keyframe);
3870 /* Get entry from index table if present */
3871 if (find_edit_entry (demux, etrack, *position, keyframe, &index_entry)) {
3872 GST_DEBUG_OBJECT (demux,
3873 "Got position %" G_GINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
3874 index_entry.dts, index_entry.offset);
3875 *position = index_entry.dts;
3876 return index_entry.offset;
3879 GST_DEBUG_OBJECT (demux, "Not found in index table");
3881 /* Fallback to track offsets */
3883 if (!demux->random_access) {
3884 /* Best effort for push mode */
3885 offset = find_closest_offset (etrack->offsets, position, keyframe);
3887 GST_DEBUG_OBJECT (demux,
3888 "Starting with edit unit %" G_GINT64_FORMAT " for %" G_GINT64_FORMAT
3889 " in generated index at offset %" G_GUINT64_FORMAT, *position,
3890 requested_position, offset);
3894 if (etrack->duration > 0 && *position >= etrack->duration) {
3895 GST_WARNING_OBJECT (demux, "Position after end of essence track");
3901 index_start_position = *position;
3903 demux->offset = demux->run_in;
3905 offset = find_closest_offset (etrack->offsets, &index_start_position, FALSE);
3907 demux->offset = offset + demux->run_in;
3908 GST_DEBUG_OBJECT (demux,
3909 "Starting with edit unit %" G_GINT64_FORMAT " for %" G_GINT64_FORMAT
3910 " in generated index at offset %" G_GUINT64_FORMAT,
3911 index_start_position, requested_position, offset);
3913 index_start_position = -1;
3916 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
3918 for (i = 0; i < demux->essence_tracks->len; i++) {
3919 GstMXFDemuxEssenceTrack *t =
3920 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
3922 if (index_start_position != -1 && t == etrack)
3923 t->position = index_start_position;
3925 t->position = (demux->offset == demux->run_in) ? 0 : -1;
3926 GST_LOG_OBJECT (demux, "Setting track %d position to %" G_GINT64_FORMAT,
3927 t->track_id, t->position);
3930 /* Else peek at all essence elements and complete our
3931 * index until we find the requested element
3933 while (ret == GST_FLOW_OK) {
3936 GST_LOG_OBJECT (demux, "Pulling from offset %" G_GINT64_FORMAT,
3938 ret = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3940 if (ret == GST_FLOW_EOS) {
3942 for (i = 0; i < demux->essence_tracks->len; i++) {
3943 GstMXFDemuxEssenceTrack *t =
3944 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
3947 if (t->position > 0)
3948 t->duration = t->position;
3950 /* For the searched track this is really our position */
3951 etrack->duration = etrack->position;
3953 for (i = 0; i < demux->src->len; i++) {
3954 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3957 && p->current_essence_track_position >=
3958 p->current_essence_track->duration) {
3962 e = gst_event_new_eos ();
3963 gst_event_set_seqnum (e, demux->seqnum);
3964 gst_pad_push_event (GST_PAD_CAST (p), e);
3969 GST_LOG_OBJECT (demux,
3970 "pulling gave flow:%s track->position:%" G_GINT64_FORMAT,
3971 gst_flow_get_name (ret), etrack->position);
3972 if (G_UNLIKELY (ret != GST_FLOW_OK) && etrack->position <= *position) {
3973 demux->offset = old_offset;
3974 demux->current_partition = old_partition;
3976 } else if (G_UNLIKELY (ret == GST_FLOW_OK)) {
3977 ret = gst_mxf_demux_handle_klv_packet (demux, &klv, TRUE);
3978 gst_mxf_demux_consume_klv (demux, &klv);
3981 GST_LOG_OBJECT (demux,
3982 "Handling gave flow:%s track->position:%" G_GINT64_FORMAT
3983 " looking for %" G_GINT64_FORMAT, gst_flow_get_name (ret),
3984 etrack->position, *position);
3986 /* If we found the position read it from the index again */
3987 if (((ret == GST_FLOW_OK && etrack->position == *position + 1) ||
3988 (ret == GST_FLOW_EOS && etrack->position == *position + 1))
3989 && etrack->offsets && etrack->offsets->len > *position
3990 && g_array_index (etrack->offsets, GstMXFDemuxIndex,
3991 *position).offset != 0) {
3992 GST_DEBUG_OBJECT (demux, "Found at offset %" G_GUINT64_FORMAT,
3994 demux->offset = old_offset;
3995 demux->current_partition = old_partition;
3996 if (find_edit_entry (demux, etrack, *position, keyframe, &index_entry)) {
3997 GST_DEBUG_OBJECT (demux,
3998 "Got position %" G_GINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
3999 index_entry.dts, index_entry.offset);
4000 *position = index_entry.dts;
4001 return index_entry.offset;
4003 goto from_track_offset;
4006 demux->offset = old_offset;
4007 demux->current_partition = old_partition;
4009 GST_DEBUG_OBJECT (demux, "Not found in this file");
4014 static GstFlowReturn
4015 gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
4018 GstFlowReturn ret = GST_FLOW_OK;
4019 gboolean force_switch = FALSE;
4021 if (demux->src->len > 0) {
4022 if (!gst_mxf_demux_get_earliest_pad (demux)) {
4024 GST_DEBUG_OBJECT (demux, "All tracks are EOS");
4029 if (demux->state == GST_MXF_DEMUX_STATE_ESSENCE) {
4030 g_assert (demux->current_partition->single_track
4031 && demux->current_partition->single_track->wrapping !=
4032 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
4033 /* Feeding essence directly (i.e. in the middle of a custom/clip KLV) */
4035 gst_mxf_demux_handle_generic_container_essence_element (demux,
4036 &demux->current_partition->clip_klv, FALSE);
4037 gst_mxf_demux_consume_klv (demux, &demux->current_partition->clip_klv);
4038 if (ret == GST_FLOW_OK
4039 && demux->current_partition->single_track->position >=
4040 demux->current_partition->single_track->duration) {
4041 /* We are done with the contents of this clip/custom wrapping, force the
4042 * switch to the next non-EOS track */
4043 GST_DEBUG_OBJECT (demux, "Single track EOS, switch");
4044 force_switch = TRUE;
4049 ret = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
4053 * Move this EOS handling to a separate function
4055 if (ret == GST_FLOW_EOS && demux->src->len > 0) {
4057 GstMXFDemuxPad *p = NULL;
4059 GST_DEBUG_OBJECT (demux, "EOS HANDLING");
4061 for (i = 0; i < demux->src->len; i++) {
4062 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4064 GST_DEBUG_OBJECT (p,
4065 "eos:%d current_essence_track_position:%" G_GINT64_FORMAT
4066 " position:%" G_GINT64_FORMAT " duration:%" G_GINT64_FORMAT, p->eos,
4067 p->current_essence_track_position,
4068 p->current_essence_track->position,
4069 p->current_essence_track->duration);
4071 && p->current_essence_track->position >=
4072 p->current_essence_track->duration) {
4076 e = gst_event_new_eos ();
4077 gst_event_set_seqnum (e, demux->seqnum);
4078 gst_pad_push_event (GST_PAD_CAST (p), e);
4082 while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
4086 GST_DEBUG_OBJECT (p, "Trying on earliest");
4088 position = p->current_essence_track_position;
4091 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
4096 GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
4098 e = gst_event_new_eos ();
4099 gst_event_set_seqnum (e, demux->seqnum);
4100 gst_pad_push_event (GST_PAD_CAST (p), e);
4104 demux->offset = offset + demux->run_in;
4105 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4106 if (p->current_essence_track->wrapping !=
4107 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4108 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4109 demux->current_partition->clip_klv.consumed =
4110 offset - demux->current_partition->clip_klv.offset;
4112 demux->state = GST_MXF_DEMUX_STATE_KLV;
4113 p->current_essence_track->position = position;
4119 if (G_UNLIKELY (ret != GST_FLOW_OK))
4122 ret = gst_mxf_demux_handle_klv_packet (demux, &klv, FALSE);
4123 gst_mxf_demux_consume_klv (demux, &klv);
4125 /* We entered a new partition */
4126 if (ret == GST_FLOW_OK && mxf_is_partition_pack (&klv.key)) {
4127 GstMXFDemuxPartition *partition = demux->current_partition;
4128 gboolean partition_done = FALSE;
4130 /* Grab footer metadata if needed */
4131 if (demux->pull_footer_metadata
4132 && partition->partition.type == MXF_PARTITION_PACK_HEADER
4133 && (!partition->partition.closed || !partition->partition.complete)
4134 && (demux->footer_partition_pack_offset != 0
4135 || demux->random_index_pack)) {
4136 GST_DEBUG_OBJECT (demux,
4137 "Open or incomplete header partition, trying to get final metadata from the last partitions");
4138 gst_mxf_demux_parse_footer_metadata (demux);
4139 demux->pull_footer_metadata = FALSE;
4142 /* If the partition has some content, do post-checks */
4143 if (partition->partition.body_sid != 0) {
4144 guint64 lowest_offset = G_MAXUINT64;
4145 GST_DEBUG_OBJECT (demux,
4146 "Entered partition (body_sid:%d index_sid:%d body_offset:%"
4147 G_GUINT64_FORMAT "), checking positions",
4148 partition->partition.body_sid, partition->partition.index_sid,
4149 partition->partition.body_offset);
4151 if (partition->single_track) {
4152 /* Fast-path for single track partition */
4153 if (partition->single_track->position == -1
4154 && partition->partition.body_offset == 0) {
4155 GST_DEBUG_OBJECT (demux,
4156 "First time in partition, setting track position to 0");
4157 partition->single_track->position = 0;
4158 } else if (partition->single_track->position == -1) {
4159 GST_ERROR_OBJECT (demux,
4160 "Unknown track position, consuming data from first partition entry");
4162 partition->partition.this_partition +
4163 partition->essence_container_offset;
4164 partition->clip_klv.consumed = 0;
4165 } else if (partition->single_track->position != 0) {
4166 GstMXFDemuxIndex entry;
4167 GST_DEBUG_OBJECT (demux,
4168 "Track already at another position : %" G_GINT64_FORMAT,
4169 partition->single_track->position);
4170 if (find_edit_entry (demux, partition->single_track,
4171 partition->single_track->position, FALSE, &entry)) {
4172 lowest_offset = entry.offset;
4173 } else if (partition->single_track->position >=
4174 partition->single_track->duration) {
4175 GST_DEBUG_OBJECT (demux, "Track fully consumed, partition done");
4176 partition_done = TRUE;
4181 for (i = 0; i < demux->essence_tracks->len; i++) {
4182 GstMXFDemuxEssenceTrack *etrack =
4183 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
4186 if (etrack->body_sid != partition->partition.body_sid)
4188 if (etrack->position == -1 && partition->partition.body_offset == 0) {
4189 GST_DEBUG_OBJECT (demux, "Resetting track %d to position 0",
4192 etrack->position = 0;
4193 } else if (etrack->position != 0) {
4194 GstMXFDemuxIndex entry;
4195 if (find_edit_entry (demux, etrack,
4196 etrack->position, FALSE, &entry)) {
4197 if (lowest_offset == G_MAXUINT64
4198 || entry.offset < lowest_offset)
4199 lowest_offset = entry.offset;
4205 if (partition_done || lowest_offset != G_MAXUINT64) {
4206 GstMXFDemuxPartition *next_partition = NULL;
4207 GList *cur_part = g_list_find (demux->partitions, partition);
4208 if (cur_part && cur_part->next)
4209 next_partition = (GstMXFDemuxPartition *) cur_part->next->data;
4211 /* If we have completely processed this partition, skip to next partition */
4213 || lowest_offset > next_partition->partition.this_partition) {
4214 GST_DEBUG_OBJECT (demux,
4215 "Partition entirely processed, skipping to next one");
4216 demux->offset = next_partition->partition.this_partition;
4218 GST_DEBUG_OBJECT (demux,
4219 "Skipping to demuxer offset %" G_GUINT64_FORMAT " (from %"
4220 G_GUINT64_FORMAT ")", lowest_offset, demux->offset);
4221 demux->offset = lowest_offset;
4222 if (partition->single_track
4223 && partition->single_track->wrapping !=
4224 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4225 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4226 demux->current_partition->clip_klv.consumed =
4227 demux->offset - demux->current_partition->clip_klv.offset;
4235 if (ret == GST_FLOW_OK && demux->src->len > 0
4236 && demux->essence_tracks->len > 0) {
4237 GstMXFDemuxPad *earliest = NULL;
4238 /* We allow time drifts of at most 500ms */
4239 while ((earliest = gst_mxf_demux_get_earliest_pad (demux)) && (force_switch
4240 || demux->segment.position - earliest->position >
4241 demux->max_drift)) {
4245 GST_DEBUG_OBJECT (demux,
4246 "Found synchronization issue -- trying to solve");
4248 position = earliest->current_essence_track_position;
4250 /* FIXME: This can probably be improved by using the
4251 * offset of position-1 if it's in the same partition
4252 * or the start of the position otherwise.
4253 * This way we won't skip elements from the same essence
4254 * container as etrack->position
4257 gst_mxf_demux_find_essence_element (demux,
4258 earliest->current_essence_track, &position, FALSE);
4262 GST_WARNING_OBJECT (demux,
4263 "Failed to find offset for late essence track");
4264 earliest->eos = TRUE;
4265 e = gst_event_new_eos ();
4266 gst_event_set_seqnum (e, demux->seqnum);
4267 gst_pad_push_event (GST_PAD_CAST (earliest), e);
4271 demux->offset = offset + demux->run_in;
4272 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4273 GST_DEBUG_OBJECT (demux,
4274 "Switching to offset %" G_GUINT64_FORMAT " for position %"
4275 G_GINT64_FORMAT " on track %d (body_sid:%d index_sid:%d)",
4276 demux->offset, position, earliest->current_essence_track->track_id,
4277 earliest->current_essence_track->body_sid,
4278 earliest->current_essence_track->index_sid);
4279 if (demux->current_partition->single_track
4280 && demux->current_partition->single_track->wrapping !=
4281 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4282 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4283 demux->current_partition->clip_klv.consumed =
4284 offset - demux->current_partition->clip_klv.offset;
4286 demux->state = GST_MXF_DEMUX_STATE_KLV;
4288 earliest->current_essence_track->position = position;
4289 GST_DEBUG_OBJECT (earliest, "Switching to this pad");
4299 gst_mxf_demux_loop (GstPad * pad)
4301 GstMXFDemux *demux = NULL;
4302 GstFlowReturn flow = GST_FLOW_OK;
4304 demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
4306 if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4309 /* Skip run-in, which is at most 64K and is finished
4310 * by a header partition pack */
4311 while (demux->offset < 64 * 1024) {
4313 gst_mxf_demux_peek_klv_packet (demux, demux->offset,
4314 &klv)) != GST_FLOW_OK)
4317 if (mxf_is_header_partition_pack (&klv.key)) {
4318 GST_DEBUG_OBJECT (demux,
4319 "Found header partition pack at offset %" G_GUINT64_FORMAT,
4321 demux->state = GST_MXF_DEMUX_STATE_KLV;
4322 demux->run_in = demux->offset;
4328 if (G_UNLIKELY (demux->run_in == -1)) {
4329 GST_ERROR_OBJECT (demux, "No valid header partition pack found");
4330 flow = GST_FLOW_ERROR;
4334 /* Grab the RIP at the end of the file (if present) */
4335 gst_mxf_demux_pull_random_index_pack (demux);
4338 /* Now actually do something */
4339 flow = gst_mxf_demux_pull_and_handle_klv_packet (demux);
4341 /* pause if something went wrong */
4342 if (G_UNLIKELY (flow != GST_FLOW_OK))
4345 /* check EOS condition */
4346 if ((demux->segment.stop != -1) &&
4347 (demux->segment.position >= demux->segment.stop)) {
4349 gboolean eos = TRUE;
4351 for (i = 0; i < demux->src->len; i++) {
4352 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4354 if (!p->eos && p->position < demux->segment.stop) {
4361 flow = GST_FLOW_EOS;
4366 gst_object_unref (demux);
4372 const gchar *reason = gst_flow_get_name (flow);
4374 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
4375 gst_pad_pause_task (pad);
4377 if (flow == GST_FLOW_EOS) {
4378 /* perform EOS logic */
4379 if (demux->src->len == 0) {
4380 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
4381 ("This stream contains no data."),
4382 ("got eos and didn't find any streams"));
4383 } else if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4388 /* for segment playback we need to post when (in stream time)
4389 * we stopped, this is either stop (when set) or the duration. */
4390 if ((stop = demux->segment.stop) == -1)
4391 stop = demux->segment.duration;
4393 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
4394 m = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
4395 GST_FORMAT_TIME, stop);
4396 gst_message_set_seqnum (m, demux->seqnum);
4397 gst_element_post_message (GST_ELEMENT_CAST (demux), m);
4398 e = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
4399 gst_event_set_seqnum (e, demux->seqnum);
4400 gst_mxf_demux_push_src_event (demux, e);
4404 /* normal playback, send EOS to all linked pads */
4405 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
4406 e = gst_event_new_eos ();
4407 gst_event_set_seqnum (e, demux->seqnum);
4408 if (!gst_mxf_demux_push_src_event (demux, e)) {
4409 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
4412 } else if (flow == GST_FLOW_NOT_LINKED || flow < GST_FLOW_EOS) {
4415 GST_ELEMENT_FLOW_ERROR (demux, flow);
4416 e = gst_event_new_eos ();
4417 gst_event_set_seqnum (e, demux->seqnum);
4418 gst_mxf_demux_push_src_event (demux, e);
4420 gst_object_unref (demux);
4425 static GstFlowReturn
4426 gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
4428 GstFlowReturn ret = GST_FLOW_OK;
4429 GstMXFDemux *demux = NULL;
4430 const guint8 *data = NULL;
4433 #ifndef GST_DISABLE_GST_DEBUG
4437 demux = GST_MXF_DEMUX (parent);
4439 GST_LOG_OBJECT (demux,
4440 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
4441 G_GUINT64_FORMAT, gst_buffer_get_size (inbuf), GST_BUFFER_OFFSET (inbuf));
4443 if (demux->src->len > 0) {
4444 if (!gst_mxf_demux_get_earliest_pad (demux)) {
4446 GST_DEBUG_OBJECT (demux, "All tracks are EOS");
4451 if (G_UNLIKELY (GST_BUFFER_OFFSET (inbuf) == 0)) {
4452 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
4455 demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
4458 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (inbuf) != 0)) {
4459 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
4460 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
4461 demux->offset = GST_BUFFER_OFFSET (inbuf);
4462 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4463 } else if (demux->current_partition == NULL) {
4464 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4467 gst_adapter_push (demux->adapter, inbuf);
4470 while (ret == GST_FLOW_OK) {
4471 if (G_UNLIKELY (demux->flushing)) {
4472 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
4473 ret = GST_FLOW_FLUSHING;
4477 if (gst_adapter_available (demux->adapter) < 16)
4480 if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4481 /* Skip run-in, which is at most 64K and is finished
4482 * by a header partition pack */
4484 while (demux->offset < 64 * 1024
4485 && gst_adapter_available (demux->adapter) >= 16) {
4486 data = gst_adapter_map (demux->adapter, 16);
4487 res = mxf_is_header_partition_pack ((const MXFUL *) data);
4488 gst_adapter_unmap (demux->adapter);
4491 GST_DEBUG_OBJECT (demux,
4492 "Found header partition pack at offset %" G_GUINT64_FORMAT,
4494 demux->run_in = demux->offset;
4495 demux->state = GST_MXF_DEMUX_STATE_KLV;
4498 gst_adapter_flush (demux->adapter, 1);
4501 } else if (demux->offset < demux->run_in) {
4502 guint64 flush = MIN (gst_adapter_available (demux->adapter),
4503 demux->run_in - demux->offset);
4504 gst_adapter_flush (demux->adapter, flush);
4505 demux->offset += flush;
4509 if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4510 /* Need more data */
4511 if (demux->offset < 64 * 1024)
4514 GST_ERROR_OBJECT (demux, "No valid header partition pack found");
4515 ret = GST_FLOW_ERROR;
4519 if (gst_adapter_available (demux->adapter) < 17)
4522 /* FIXME : Handle non-klv state */
4523 g_assert (demux->state == GST_MXF_DEMUX_STATE_KLV);
4525 /* Now actually do something */
4526 memset (&klv, 0, sizeof (GstMXFKLV));
4528 /* Pull 16 byte key and first byte of BER encoded length */
4529 data = gst_adapter_map (demux->adapter, 17);
4531 memcpy (&klv.key, data, 16);
4533 GST_DEBUG_OBJECT (demux, "Got KLV packet with key %s",
4534 mxf_ul_to_string (&klv.key, str));
4536 /* Decode BER encoded packet length */
4537 if ((data[16] & 0x80) == 0) {
4538 klv.length = data[16];
4539 klv.data_offset = 17;
4541 guint slen = data[16] & 0x7f;
4543 klv.data_offset = 16 + 1 + slen;
4545 gst_adapter_unmap (demux->adapter);
4547 /* Must be at most 8 according to SMPTE-379M 5.3.4 and
4548 * GStreamer buffers can only have a 4 bytes length */
4550 GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
4551 ret = GST_FLOW_ERROR;
4555 if (gst_adapter_available (demux->adapter) < 17 + slen)
4558 data = gst_adapter_map (demux->adapter, 17 + slen);
4563 klv.length = (klv.length << 8) | *data;
4569 gst_adapter_unmap (demux->adapter);
4571 /* GStreamer's buffer sizes are stored in a guint so we
4572 * limit ourself to G_MAXUINT large buffers */
4573 if (klv.length > G_MAXUINT) {
4574 GST_ERROR_OBJECT (demux,
4575 "Unsupported KLV packet length: %" G_GSIZE_FORMAT, klv.length);
4576 ret = GST_FLOW_ERROR;
4580 GST_DEBUG_OBJECT (demux, "KLV packet with key %s has length "
4581 "%" G_GSIZE_FORMAT, mxf_ul_to_string (&klv.key, str), klv.length);
4583 if (gst_adapter_available (demux->adapter) < klv.data_offset + klv.length)
4586 gst_adapter_flush (demux->adapter, klv.data_offset);
4588 if (klv.length > 0) {
4589 klv.data = gst_adapter_take_buffer (demux->adapter, klv.length);
4591 ret = gst_mxf_demux_handle_klv_packet (demux, &klv, FALSE);
4593 gst_mxf_demux_consume_klv (demux, &klv);
4599 /* Given a stream time for an output pad, figure out:
4600 * * The Essence track for that stream time
4601 * * The position on that track
4604 gst_mxf_demux_pad_to_track_and_position (GstMXFDemux * demux,
4605 GstMXFDemuxPad * pad, GstClockTime streamtime,
4606 GstMXFDemuxEssenceTrack ** etrack, gint64 * position)
4608 gint64 material_position;
4611 MXFMetadataSourceClip *clip = NULL;
4614 /* Convert to material position */
4616 gst_util_uint64_scale (streamtime, pad->material_track->edit_rate.n,
4617 pad->material_track->edit_rate.d * GST_SECOND);
4619 GST_DEBUG_OBJECT (pad,
4620 "streamtime %" GST_TIME_FORMAT " position %" G_GINT64_FORMAT,
4621 GST_TIME_ARGS (streamtime), material_position);
4624 /* Find sequence component covering that position */
4625 for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
4628 MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
4629 structural_components[i]);
4630 GST_LOG_OBJECT (pad,
4631 "clip %d start_position:%" G_GINT64_FORMAT " duration %"
4632 G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
4633 clip->parent.duration);
4634 if (clip->parent.duration <= 0)
4636 if ((sum + clip->parent.duration) > material_position)
4638 sum += clip->parent.duration;
4641 if (i == pad->material_track->parent.sequence->n_structural_components) {
4642 GST_WARNING_OBJECT (pad, "Requested position beyond the last clip");
4643 /* Outside of current components. Setting to the end of the last clip */
4644 material_position = sum;
4645 sum -= clip->parent.duration;
4648 GST_DEBUG_OBJECT (pad, "Looking for essence track for track_id:%d umid:%s",
4649 clip->source_track_id, mxf_umid_to_string (&clip->source_package_id,
4652 /* Get the corresponding essence track for the given source package and stream id */
4653 for (i = 0; i < demux->essence_tracks->len; i++) {
4654 GstMXFDemuxEssenceTrack *track =
4655 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
4656 GST_LOG_OBJECT (pad,
4657 "Looking at essence track body_sid:%d index_sid:%d",
4658 track->body_sid, track->index_sid);
4659 if (clip->source_track_id == 0 || (track->track_id == clip->source_track_id
4660 && mxf_umid_is_equal (&clip->source_package_id,
4661 &track->source_package_uid))) {
4662 GST_DEBUG_OBJECT (pad,
4663 "Found matching essence track body_sid:%d index_sid:%d",
4664 track->body_sid, track->index_sid);
4666 *position = material_position - sum;
4674 /* Given a track+position for a given pad, figure out the resulting stream time */
4676 gst_mxf_demux_pad_get_stream_time (GstMXFDemux * demux,
4677 GstMXFDemuxPad * pad, GstMXFDemuxEssenceTrack * etrack,
4678 gint64 position, GstClockTime * stream_time)
4682 MXFMetadataSourceClip *clip = NULL;
4684 /* Find the component for that */
4685 /* Find sequence component covering that position */
4686 for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
4689 MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
4690 structural_components[i]);
4691 GST_LOG_OBJECT (pad,
4692 "clip %d start_position:%" G_GINT64_FORMAT " duration %"
4693 G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
4694 clip->parent.duration);
4695 if (etrack->track_id == clip->source_track_id
4696 && mxf_umid_is_equal (&clip->source_package_id,
4697 &etrack->source_package_uid)) {
4698 /* This is the clip */
4701 /* Fetch in the next one */
4702 sum += clip->parent.duration;
4705 /* Theoretically impossible */
4706 if (i == pad->material_track->parent.sequence->n_structural_components) {
4707 /* Outside of current components ?? */
4712 gst_util_uint64_scale (position + sum,
4713 pad->material_track->edit_rate.d * GST_SECOND,
4714 pad->material_track->edit_rate.n);
4720 gst_mxf_demux_pad_set_position (GstMXFDemux * demux, GstMXFDemuxPad * p,
4725 MXFMetadataSourceClip *clip = NULL;
4727 if (!p->current_component) {
4728 p->current_essence_track_position =
4729 gst_util_uint64_scale (start, p->material_track->edit_rate.n,
4730 p->material_track->edit_rate.d * GST_SECOND);
4732 if (p->current_essence_track_position >= p->current_essence_track->duration
4733 && p->current_essence_track->duration > 0) {
4734 p->current_essence_track_position = p->current_essence_track->duration;
4736 gst_util_uint64_scale (p->current_essence_track->duration,
4737 p->material_track->edit_rate.d * GST_SECOND,
4738 p->material_track->edit_rate.n);
4740 p->position = start;
4742 p->position_accumulated_error = 0.0;
4743 p->current_material_track_position = p->current_essence_track_position;
4748 for (i = 0; i < p->material_track->parent.sequence->n_structural_components;
4751 MXF_METADATA_SOURCE_CLIP (p->material_track->parent.sequence->
4752 structural_components[i]);
4754 if (clip->parent.duration <= 0)
4757 sum += clip->parent.duration;
4759 if (gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4760 p->material_track->edit_rate.n) > start)
4764 if (i == p->material_track->parent.sequence->n_structural_components) {
4766 gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4767 p->material_track->edit_rate.n);
4768 p->position_accumulated_error = 0.0;
4769 p->current_material_track_position = sum;
4771 gst_mxf_demux_pad_set_component (demux, p, i);
4775 if (clip->parent.duration > 0)
4776 sum -= clip->parent.duration;
4779 gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4780 p->material_track->edit_rate.n);
4782 gst_mxf_demux_pad_set_component (demux, p, i);
4785 gint64 essence_offset = gst_util_uint64_scale (start,
4786 p->current_essence_track->source_track->edit_rate.n,
4787 p->current_essence_track->source_track->edit_rate.d * GST_SECOND);
4789 p->current_essence_track_position += essence_offset;
4791 p->position = gst_util_uint64_scale (sum,
4792 GST_SECOND * p->material_track->edit_rate.d,
4793 p->material_track->edit_rate.n) + gst_util_uint64_scale (essence_offset,
4794 GST_SECOND * p->current_essence_track->source_track->edit_rate.d,
4795 p->current_essence_track->source_track->edit_rate.n);
4796 p->position_accumulated_error = 0.0;
4797 p->current_material_track_position = sum + essence_offset;
4800 if (p->current_essence_track_position >= p->current_essence_track->duration
4801 && p->current_essence_track->duration > 0) {
4802 p->current_essence_track_position = p->current_essence_track->duration;
4804 gst_util_uint64_scale (sum + p->current_component->parent.duration,
4805 p->material_track->edit_rate.d * GST_SECOND,
4806 p->material_track->edit_rate.n);
4807 p->position_accumulated_error = 0.0;
4808 p->current_material_track_position =
4809 sum + p->current_component->parent.duration;
4814 gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event)
4818 GstSeekType start_type, stop_type;
4821 gboolean update, flush, keyframe;
4822 GstSegment seeksegment;
4826 gst_event_parse_seek (event, &rate, &format, &flags,
4827 &start_type, &start, &stop_type, &stop);
4828 seqnum = gst_event_get_seqnum (event);
4833 if (format != GST_FORMAT_TIME)
4836 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
4837 keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
4839 /* Work on a copy until we are sure the seek succeeded. */
4840 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
4842 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
4845 /* Apply the seek to our segment */
4846 gst_segment_do_seek (&seeksegment, rate, format, flags,
4847 start_type, start, stop_type, stop, &update);
4849 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
4852 if (flush || seeksegment.position != demux->segment.position) {
4854 guint64 new_offset = -1;
4857 if (!demux->metadata_resolved || demux->update_metadata) {
4858 if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
4859 gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
4860 goto unresolved_metadata;
4864 /* Do the actual seeking */
4865 for (i = 0; i < demux->src->len; i++) {
4866 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4870 /* Reset EOS flag on all pads */
4872 gst_mxf_demux_pad_set_position (demux, p, start);
4874 position = p->current_essence_track_position;
4875 off = gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
4876 &position, keyframe);
4877 new_offset = MIN (off, new_offset);
4881 if (new_offset == -1)
4884 new_offset += demux->run_in;
4886 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
4887 G_GUINT64_FORMAT, new_offset);
4888 e = gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
4889 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
4890 new_offset, GST_SEEK_TYPE_NONE, 0);
4891 gst_event_set_seqnum (e, seqnum);
4892 ret = gst_pad_push_event (demux->sinkpad, e);
4894 if (G_UNLIKELY (!ret)) {
4899 /* Tell all the stream a new segment is needed */
4900 for (i = 0; i < demux->src->len; i++) {
4901 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4902 p->need_segment = TRUE;
4905 for (i = 0; i < demux->essence_tracks->len; i++) {
4906 GstMXFDemuxEssenceTrack *t =
4907 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
4911 /* Ok seek succeeded, take the newly configured segment */
4912 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
4919 GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
4920 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4924 GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
4927 unresolved_metadata:
4929 GST_WARNING_OBJECT (demux, "metadata can't be resolved");
4930 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4934 GST_WARNING_OBJECT (demux, "upstream seek failed");
4935 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4939 GST_WARNING_OBJECT (demux, "can't find new offset");
4940 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4945 collect_index_table_segments (GstMXFDemux * demux)
4949 guint64 old_offset = demux->offset;
4950 GstMXFDemuxPartition *old_partition = demux->current_partition;
4952 /* This function can also be called when a RIP is not present. This can happen
4953 * if index table segments were discovered while scanning the file */
4954 if (demux->random_index_pack) {
4955 for (i = 0; i < demux->random_index_pack->len; i++) {
4956 MXFRandomIndexPackEntry *e =
4957 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry, i);
4959 if (e->offset < demux->run_in) {
4960 GST_ERROR_OBJECT (demux, "Invalid random index pack entry");
4964 demux->offset = e->offset;
4965 read_partition_header (demux);
4968 demux->offset = old_offset;
4969 demux->current_partition = old_partition;
4972 if (demux->pending_index_table_segments == NULL) {
4973 GST_DEBUG_OBJECT (demux, "No pending index table segments to collect");
4977 GST_LOG_OBJECT (demux, "Collecting pending index table segments");
4979 for (l = demux->pending_index_table_segments; l; l = l->next) {
4980 MXFIndexTableSegment *segment = l->data;
4981 GstMXFDemuxIndexTable *t = NULL;
4984 #ifndef GST_DISABLE_GST_DEBUG
4988 GST_LOG_OBJECT (demux,
4989 "Collecting from segment bodySID:%d indexSID:%d instance_id: %s",
4990 segment->body_sid, segment->index_sid,
4991 mxf_uuid_to_string (&segment->instance_id, str));
4993 for (k = demux->index_tables; k; k = k->next) {
4994 GstMXFDemuxIndexTable *tmp = k->data;
4996 if (tmp->body_sid == segment->body_sid
4997 && tmp->index_sid == segment->index_sid) {
5004 t = g_new0 (GstMXFDemuxIndexTable, 1);
5005 t->body_sid = segment->body_sid;
5006 t->index_sid = segment->index_sid;
5007 t->max_temporal_offset = 0;
5008 t->segments = g_array_new (FALSE, TRUE, sizeof (MXFIndexTableSegment));
5009 g_array_set_clear_func (t->segments,
5010 (GDestroyNotify) mxf_index_table_segment_reset);
5011 t->reordered_delta_entry = -1;
5012 t->reverse_temporal_offsets = g_array_new (FALSE, TRUE, 1);
5013 demux->index_tables = g_list_prepend (demux->index_tables, t);
5016 /* Store index segment */
5017 g_array_append_val (t->segments, *segment);
5019 /* Check if temporal reordering tables should be pre-calculated */
5020 for (didx = 0; didx < segment->n_delta_entries; didx++) {
5021 MXFDeltaEntry *delta = &segment->delta_entries[didx];
5022 if (delta->pos_table_index == -1) {
5023 if (t->reordered_delta_entry != -1 && didx != t->reordered_delta_entry)
5024 GST_WARNING_OBJECT (demux,
5025 "Index Table specifies more than one stream using temporal reordering (%d and %d)",
5026 didx, t->reordered_delta_entry);
5028 t->reordered_delta_entry = didx;
5029 } else if (delta->pos_table_index > 0)
5030 GST_WARNING_OBJECT (delta,
5031 "Index Table uses fractional offset, please file a bug");
5036 /* Handle temporal offset if present and needed */
5037 for (l = demux->index_tables; l; l = l->next) {
5038 GstMXFDemuxIndexTable *table = l->data;
5041 /* No reordered entries, skip */
5042 if (table->reordered_delta_entry == -1)
5045 GST_DEBUG_OBJECT (demux,
5046 "bodySID:%d indexSID:%d Calculating reverse temporal offset table",
5047 table->body_sid, table->index_sid);
5049 for (segidx = 0; segidx < table->segments->len; segidx++) {
5050 MXFIndexTableSegment *s =
5051 &g_array_index (table->segments, MXFIndexTableSegment, segidx);
5052 guint start = s->index_start_position;
5054 s->index_duration ? start + s->index_duration : start +
5058 if (stop > table->reverse_temporal_offsets->len)
5059 g_array_set_size (table->reverse_temporal_offsets, stop);
5061 for (entidx = 0; entidx < s->n_index_entries; entidx++) {
5062 MXFIndexEntry *entry = &s->index_entries[entidx];
5063 gint8 offs = -entry->temporal_offset;
5064 /* Check we don't exceed boundaries */
5065 if ((start + entidx + entry->temporal_offset) < 0 ||
5066 (start + entidx + entry->temporal_offset) >
5067 table->reverse_temporal_offsets->len) {
5068 GST_ERROR_OBJECT (demux,
5069 "Temporal offset exceeds boundaries. entry:%d offset:%d max:%d",
5070 start + entidx, entry->temporal_offset,
5071 table->reverse_temporal_offsets->len);
5073 /* Applying the temporal offset gives us the entry that should contain this PTS.
5074 * We store the reverse temporal offset on that entry, i.e. the value it should apply
5075 * to go from DTS to PTS. (i.e. entry.pts = entry.dts + rto[idx]) */
5076 g_array_index (table->reverse_temporal_offsets, gint8,
5077 start + entidx + entry->temporal_offset) = offs;
5078 if (entry->temporal_offset > (gint) table->max_temporal_offset) {
5079 GST_LOG_OBJECT (demux,
5080 "Updating max temporal offset to %d (was %d)",
5081 entry->temporal_offset, table->max_temporal_offset);
5082 table->max_temporal_offset = entry->temporal_offset;
5089 g_list_free_full (demux->pending_index_table_segments, g_free);
5090 demux->pending_index_table_segments = NULL;
5092 GST_DEBUG_OBJECT (demux, "Done collecting segments");
5096 gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
5098 GstClockTime keyunit_ts;
5101 GstSeekType start_type, stop_type;
5104 gboolean update, flush, keyframe;
5105 GstSegment seeksegment;
5107 gboolean ret = TRUE;
5110 gst_event_parse_seek (event, &rate, &format, &flags,
5111 &start_type, &start, &stop_type, &stop);
5112 seqnum = gst_event_get_seqnum (event);
5114 if (seqnum == demux->seqnum) {
5115 GST_DEBUG_OBJECT (demux, "Already handled requested seek");
5119 GST_DEBUG_OBJECT (demux, "Seek %" GST_PTR_FORMAT, event);
5121 if (format != GST_FORMAT_TIME)
5127 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
5128 keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
5130 if (!demux->index_table_segments_collected) {
5131 collect_index_table_segments (demux);
5132 demux->index_table_segments_collected = TRUE;
5138 /* Flush start up and downstream to make sure data flow and loops are
5140 e = gst_event_new_flush_start ();
5141 gst_event_set_seqnum (e, seqnum);
5142 gst_mxf_demux_push_src_event (demux, gst_event_ref (e));
5143 gst_pad_push_event (demux->sinkpad, e);
5145 /* Pause the pulling task */
5146 gst_pad_pause_task (demux->sinkpad);
5149 /* Take the stream lock */
5150 GST_PAD_STREAM_LOCK (demux->sinkpad);
5155 /* Stop flushing upstream we need to pull */
5156 e = gst_event_new_flush_stop (TRUE);
5157 gst_event_set_seqnum (e, seqnum);
5158 gst_pad_push_event (demux->sinkpad, e);
5161 /* Work on a copy until we are sure the seek succeeded. */
5162 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
5164 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
5167 /* Apply the seek to our segment */
5168 gst_segment_do_seek (&seeksegment, rate, format, flags,
5169 start_type, start, stop_type, stop, &update);
5171 GST_DEBUG_OBJECT (demux,
5172 "segment initially configured to %" GST_SEGMENT_FORMAT, &seeksegment);
5174 /* Initialize and reset ourselves if needed */
5175 if (flush || seeksegment.position != demux->segment.position) {
5177 if (!demux->metadata_resolved || demux->update_metadata) {
5178 if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
5179 gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
5180 goto unresolved_metadata;
5184 /* Reset all single-track KLV tracking */
5185 for (tmp = demux->partitions; tmp; tmp = tmp->next) {
5186 GstMXFDemuxPartition *partition = (GstMXFDemuxPartition *) tmp->data;
5187 if (partition->single_track) {
5188 partition->clip_klv.consumed = 0;
5193 keyunit_ts = seeksegment.position;
5195 /* Do a first round without changing positions. This is needed to figure out
5196 * the supporting keyframe position (if any) */
5197 for (i = 0; i < demux->src->len; i++) {
5198 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5199 GstMXFDemuxEssenceTrack *etrack;
5200 gint64 track_pos, seeked_pos;
5202 /* Get track and track position for requested time, handles out of bound internally */
5203 if (!gst_mxf_demux_pad_to_track_and_position (demux, p,
5204 seeksegment.position, &etrack, &track_pos))
5205 goto invalid_position;
5208 "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT,
5209 etrack->track_id, etrack->body_sid, etrack->index_sid, track_pos);
5211 /* Find supporting keyframe entry */
5212 seeked_pos = track_pos;
5213 if (gst_mxf_demux_find_essence_element (demux, etrack, &seeked_pos,
5215 /* Couldn't find entry, ignore */
5220 "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT
5221 " entry position %" G_GINT64_FORMAT, etrack->track_id, etrack->body_sid,
5222 etrack->index_sid, track_pos, seeked_pos);
5224 if (seeked_pos != track_pos) {
5225 GstClockTime stream_time;
5226 if (!gst_mxf_demux_pad_get_stream_time (demux, p, etrack, seeked_pos,
5228 goto invalid_position;
5229 GST_LOG_OBJECT (p, "Need to seek to stream time %" GST_TIME_FORMAT,
5230 GST_TIME_ARGS (stream_time));
5231 keyunit_ts = MIN (seeksegment.position, stream_time);
5235 if (keyframe && keyunit_ts != seeksegment.position) {
5236 GST_INFO_OBJECT (demux, "key unit seek, adjusting segment start to "
5237 "%" GST_TIME_FORMAT, GST_TIME_ARGS (keyunit_ts));
5238 gst_segment_do_seek (&seeksegment, rate, format, flags,
5239 start_type, keyunit_ts, stop_type, stop, &update);
5242 /* Finally set the position to the calculated position */
5243 if (flush || keyunit_ts != demux->segment.position) {
5244 guint64 new_offset = -1;
5246 /* Do the actual seeking */
5247 for (i = 0; i < demux->src->len; i++) {
5248 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5252 /* Reset EOS flag on all pads */
5254 gst_mxf_demux_pad_set_position (demux, p, seeksegment.position);
5256 /* we always want to send data starting with a key unit */
5257 position = p->current_essence_track_position;
5259 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
5262 GST_DEBUG_OBJECT (demux, "Unable to find offset for pad %s",
5264 p->current_essence_track_position = p->current_essence_track->duration;
5266 new_offset = MIN (off, new_offset);
5267 if (position != p->current_essence_track_position) {
5269 gst_util_uint64_scale (p->current_essence_track_position -
5271 GST_SECOND * p->current_essence_track->source_track->edit_rate.d,
5272 p->current_essence_track->source_track->edit_rate.n);
5273 p->position_accumulated_error = 0.0;
5274 p->current_material_track_position -=
5275 gst_util_uint64_scale (p->current_essence_track_position -
5277 p->material_track->edit_rate.n *
5278 p->current_essence_track->source_track->edit_rate.d,
5279 p->material_track->edit_rate.d *
5280 p->current_essence_track->source_track->edit_rate.n);
5282 p->current_essence_track_position = position;
5284 p->current_essence_track->position = p->current_essence_track_position;
5287 gst_flow_combiner_reset (demux->flowcombiner);
5288 if (new_offset == -1) {
5289 GST_WARNING_OBJECT (demux, "No new offset found");
5292 demux->offset = new_offset + demux->run_in;
5294 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
5295 /* Reset the state accordingly */
5296 if (demux->current_partition->single_track
5297 && demux->current_partition->single_track->wrapping !=
5298 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING)
5299 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
5301 demux->state = GST_MXF_DEMUX_STATE_KLV;
5304 if (G_UNLIKELY (demux->close_seg_event)) {
5305 gst_event_unref (demux->close_seg_event);
5306 demux->close_seg_event = NULL;
5312 /* Stop flushing, the sinks are at time 0 now */
5313 e = gst_event_new_flush_stop (TRUE);
5314 gst_event_set_seqnum (e, seqnum);
5315 gst_mxf_demux_push_src_event (demux, e);
5317 GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
5320 /* Close the current segment for a linear playback */
5321 demux->close_seg_event = gst_event_new_segment (&demux->segment);
5322 gst_event_set_seqnum (demux->close_seg_event, demux->seqnum);
5325 /* Ok seek succeeded, take the newly configured segment */
5326 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
5328 /* Notify about the start of a new segment */
5329 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5332 m = gst_message_new_segment_start (GST_OBJECT (demux),
5333 demux->segment.format, demux->segment.position);
5334 gst_message_set_seqnum (m, seqnum);
5335 gst_element_post_message (GST_ELEMENT (demux), m);
5338 /* Tell all the stream a new segment is needed */
5339 for (i = 0; i < demux->src->len; i++) {
5340 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5341 p->need_segment = TRUE;
5344 for (i = 0; i < demux->essence_tracks->len; i++) {
5345 GstMXFDemuxEssenceTrack *t =
5346 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
5350 demux->seqnum = seqnum;
5352 gst_pad_start_task (demux->sinkpad,
5353 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5355 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5362 GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
5367 GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
5370 unresolved_metadata:
5372 gst_pad_start_task (demux->sinkpad,
5373 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5374 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5375 GST_WARNING_OBJECT (demux, "metadata can't be resolved");
5384 /* Stop flushing, the sinks are at time 0 now */
5385 e = gst_event_new_flush_stop (TRUE);
5386 gst_event_set_seqnum (e, seqnum);
5387 gst_mxf_demux_push_src_event (demux, e);
5389 gst_pad_start_task (demux->sinkpad,
5390 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5391 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5392 GST_WARNING_OBJECT (demux, "Requested seek position is not valid");
5398 gst_mxf_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
5400 GstMXFDemux *demux = GST_MXF_DEMUX (parent);
5403 GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
5405 switch (GST_EVENT_TYPE (event)) {
5406 case GST_EVENT_SEEK:
5407 if (demux->random_access)
5408 ret = gst_mxf_demux_seek_pull (demux, event);
5410 ret = gst_mxf_demux_seek_push (demux, event);
5411 gst_event_unref (event);
5414 ret = gst_pad_push_event (demux->sinkpad, event);
5422 gst_mxf_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
5424 GstMXFDemux *demux = GST_MXF_DEMUX (parent);
5425 gboolean ret = FALSE;
5426 GstMXFDemuxPad *mxfpad = GST_MXF_DEMUX_PAD (pad);
5428 GST_DEBUG_OBJECT (pad, "handling query %s",
5429 gst_query_type_get_name (GST_QUERY_TYPE (query)));
5431 switch (GST_QUERY_TYPE (query)) {
5432 case GST_QUERY_POSITION:
5437 gst_query_parse_position (query, &format, NULL);
5438 if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
5443 GST_FORMAT_DEFAULT ? mxfpad->current_material_track_position :
5446 GST_DEBUG_OBJECT (pad,
5447 "Returning position %" G_GINT64_FORMAT " in format %s", pos,
5448 gst_format_get_name (format));
5450 gst_query_set_position (query, format, pos);
5455 case GST_QUERY_DURATION:{
5459 gst_query_parse_duration (query, &format, NULL);
5460 if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
5463 g_rw_lock_reader_lock (&demux->metadata_lock);
5464 if (!mxfpad->material_track || !mxfpad->material_track->parent.sequence) {
5465 g_rw_lock_reader_unlock (&demux->metadata_lock);
5469 duration = mxfpad->material_track->parent.sequence->duration;
5473 if (duration != -1 && format == GST_FORMAT_TIME) {
5474 if (mxfpad->material_track->edit_rate.n == 0 ||
5475 mxfpad->material_track->edit_rate.d == 0) {
5476 g_rw_lock_reader_unlock (&demux->metadata_lock);
5481 gst_util_uint64_scale (duration,
5482 GST_SECOND * mxfpad->material_track->edit_rate.d,
5483 mxfpad->material_track->edit_rate.n);
5485 g_rw_lock_reader_unlock (&demux->metadata_lock);
5487 GST_DEBUG_OBJECT (pad,
5488 "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
5489 gst_format_get_name (format));
5491 gst_query_set_duration (query, format, duration);
5495 case GST_QUERY_SEEKING:{
5500 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
5501 if (fmt != GST_FORMAT_TIME) {
5502 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5506 if (!gst_pad_query_duration (pad, GST_FORMAT_TIME, &duration)) {
5507 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5511 if (demux->random_access) {
5512 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, duration);
5514 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
5517 seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
5519 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
5521 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, duration);
5523 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
5525 gst_query_unref (peerquery);
5530 case GST_QUERY_SEGMENT:{
5534 format = demux->segment.format;
5537 gst_segment_to_stream_time (&demux->segment, format,
5538 demux->segment.start);
5539 if ((stop = demux->segment.stop) == -1)
5540 stop = demux->segment.duration;
5542 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
5544 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
5549 ret = gst_pad_query_default (pad, parent, query);
5559 GST_DEBUG_OBJECT (pad, "query failed");
5565 gst_mxf_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
5568 GstPadMode mode = GST_PAD_MODE_PUSH;
5570 query = gst_query_new_scheduling ();
5572 if (gst_pad_peer_query (sinkpad, query)) {
5573 if (gst_query_has_scheduling_mode_with_flags (query,
5574 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE)) {
5575 GstSchedulingFlags flags;
5576 gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
5577 if (!(flags & GST_SCHEDULING_FLAG_SEQUENTIAL))
5578 mode = GST_PAD_MODE_PULL;
5581 gst_query_unref (query);
5583 return gst_pad_activate_mode (sinkpad, mode, TRUE);
5587 gst_mxf_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5588 GstPadMode mode, gboolean active)
5592 demux = GST_MXF_DEMUX (parent);
5594 if (mode == GST_PAD_MODE_PUSH) {
5595 demux->random_access = FALSE;
5598 demux->random_access = TRUE;
5599 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_mxf_demux_loop,
5602 demux->random_access = FALSE;
5603 return gst_pad_stop_task (sinkpad);
5611 gst_mxf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
5614 gboolean ret = FALSE;
5616 demux = GST_MXF_DEMUX (parent);
5618 GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
5620 switch (GST_EVENT_TYPE (event)) {
5621 case GST_EVENT_FLUSH_START:
5622 demux->flushing = TRUE;
5623 ret = gst_pad_event_default (pad, parent, event);
5625 case GST_EVENT_FLUSH_STOP:
5626 GST_DEBUG_OBJECT (demux, "flushing queued data in the MXF demuxer");
5628 gst_adapter_clear (demux->adapter);
5629 demux->flushing = FALSE;
5631 ret = gst_pad_event_default (pad, parent, event);
5633 case GST_EVENT_EOS:{
5634 GstMXFDemuxPad *p = NULL;
5637 if (demux->src->len == 0) {
5638 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
5639 ("This stream contains no data."),
5640 ("got eos and didn't find any streams"));
5643 for (i = 0; i < demux->essence_tracks->len; i++) {
5644 GstMXFDemuxEssenceTrack *t =
5645 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
5647 if (t->position > 0)
5648 t->duration = t->position;
5651 for (i = 0; i < demux->src->len; i++) {
5652 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5655 && p->current_essence_track_position >=
5656 p->current_essence_track->duration) {
5658 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5662 while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
5666 position = p->current_essence_track_position;
5669 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
5672 GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
5674 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5678 if (gst_pad_push_event (demux->sinkpad,
5679 gst_event_new_seek (demux->segment.rate, GST_FORMAT_BYTES,
5680 demux->segment.flags | GST_SEEK_FLAG_ACCURATE,
5681 GST_SEEK_TYPE_SET, offset + demux->run_in,
5682 GST_SEEK_TYPE_NONE, 0))) {
5684 for (i = 0; i < demux->essence_tracks->len; i++) {
5685 GstMXFDemuxEssenceTrack *etrack =
5686 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
5688 etrack->position = -1;
5693 GST_WARNING_OBJECT (demux,
5694 "Seek to remaining part of the file failed");
5696 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5701 /* and one more time for good measure apparently? */
5702 gst_pad_event_default (pad, parent, event);
5703 ret = (demux->src->len > 0);
5706 case GST_EVENT_SEGMENT:{
5709 for (i = 0; i < demux->essence_tracks->len; i++) {
5710 GstMXFDemuxEssenceTrack *t =
5711 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
5715 demux->current_partition = NULL;
5716 demux->seqnum = gst_event_get_seqnum (event);
5717 gst_event_unref (event);
5722 ret = gst_pad_event_default (pad, parent, event);
5732 gst_mxf_demux_query (GstElement * element, GstQuery * query)
5734 GstMXFDemux *demux = GST_MXF_DEMUX (element);
5735 gboolean ret = FALSE;
5737 GST_DEBUG_OBJECT (demux, "handling query %s",
5738 gst_query_type_get_name (GST_QUERY_TYPE (query)));
5740 switch (GST_QUERY_TYPE (query)) {
5741 case GST_QUERY_POSITION:
5746 gst_query_parse_position (query, &format, NULL);
5747 if (format != GST_FORMAT_TIME)
5750 pos = demux->segment.position;
5752 GST_DEBUG_OBJECT (demux,
5753 "Returning position %" G_GINT64_FORMAT " in format %s", pos,
5754 gst_format_get_name (format));
5756 gst_query_set_position (query, format, pos);
5761 case GST_QUERY_DURATION:{
5762 gint64 duration = -1;
5766 gst_query_parse_duration (query, &format, NULL);
5767 if (format != GST_FORMAT_TIME)
5770 if (demux->src->len == 0)
5773 g_rw_lock_reader_lock (&demux->metadata_lock);
5774 for (i = 0; i < demux->src->len; i++) {
5775 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
5778 if (!pad->material_track || !pad->material_track->parent.sequence)
5781 pdur = pad->material_track->parent.sequence->duration;
5782 if (pad->material_track->edit_rate.n == 0 ||
5783 pad->material_track->edit_rate.d == 0 || pdur <= -1)
5787 gst_util_uint64_scale (pdur,
5788 GST_SECOND * pad->material_track->edit_rate.d,
5789 pad->material_track->edit_rate.n);
5790 duration = MAX (duration, pdur);
5792 g_rw_lock_reader_unlock (&demux->metadata_lock);
5794 if (duration == -1) {
5795 GST_DEBUG_OBJECT (demux, "No duration known (yet)");
5799 GST_DEBUG_OBJECT (demux,
5800 "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
5801 gst_format_get_name (format));
5803 gst_query_set_duration (query, format, duration);
5807 case GST_QUERY_SEEKING:{
5811 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
5812 if (fmt != GST_FORMAT_TIME) {
5813 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5817 if (demux->random_access) {
5818 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
5820 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
5823 seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
5825 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
5827 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
5829 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
5831 gst_query_unref (peerquery);
5836 case GST_QUERY_SEGMENT:{
5840 format = demux->segment.format;
5843 gst_segment_to_stream_time (&demux->segment, format,
5844 demux->segment.start);
5845 if ((stop = demux->segment.stop) == -1)
5846 stop = demux->segment.duration;
5848 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
5850 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
5855 /* else forward upstream */
5856 ret = gst_pad_peer_query (demux->sinkpad, query);
5866 GST_DEBUG_OBJECT (demux, "query failed");
5871 static GstStateChangeReturn
5872 gst_mxf_demux_change_state (GstElement * element, GstStateChange transition)
5874 GstMXFDemux *demux = GST_MXF_DEMUX (element);
5875 GstStateChangeReturn ret;
5877 switch (transition) {
5878 case GST_STATE_CHANGE_READY_TO_PAUSED:
5879 demux->seqnum = gst_util_seqnum_next ();
5885 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
5886 if (ret == GST_STATE_CHANGE_FAILURE)
5889 switch (transition) {
5890 case GST_STATE_CHANGE_PAUSED_TO_READY:
5891 gst_mxf_demux_reset (demux);
5901 gst_mxf_demux_set_property (GObject * object, guint prop_id,
5902 const GValue * value, GParamSpec * pspec)
5904 GstMXFDemux *demux = GST_MXF_DEMUX (object);
5908 g_free (demux->requested_package_string);
5909 demux->requested_package_string = g_value_dup_string (value);
5911 case PROP_MAX_DRIFT:
5912 demux->max_drift = g_value_get_uint64 (value);
5915 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5921 gst_mxf_demux_get_property (GObject * object, guint prop_id,
5922 GValue * value, GParamSpec * pspec)
5924 GstMXFDemux *demux = GST_MXF_DEMUX (object);
5928 g_value_set_string (value, demux->current_package_string);
5930 case PROP_MAX_DRIFT:
5931 g_value_set_uint64 (value, demux->max_drift);
5933 case PROP_STRUCTURE:{
5936 g_rw_lock_reader_lock (&demux->metadata_lock);
5937 if (demux->preface &&
5938 MXF_METADATA_BASE (demux->preface)->resolved ==
5939 MXF_METADATA_BASE_RESOLVE_STATE_SUCCESS)
5940 s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
5944 gst_value_set_structure (value, s);
5947 gst_structure_free (s);
5949 g_rw_lock_reader_unlock (&demux->metadata_lock);
5953 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5959 gst_mxf_demux_finalize (GObject * object)
5961 GstMXFDemux *demux = GST_MXF_DEMUX (object);
5963 gst_mxf_demux_reset (demux);
5965 if (demux->adapter) {
5966 g_object_unref (demux->adapter);
5967 demux->adapter = NULL;
5970 if (demux->flowcombiner) {
5971 gst_flow_combiner_free (demux->flowcombiner);
5972 demux->flowcombiner = NULL;
5975 if (demux->close_seg_event) {
5976 gst_event_unref (demux->close_seg_event);
5977 demux->close_seg_event = NULL;
5980 g_free (demux->current_package_string);
5981 demux->current_package_string = NULL;
5982 g_free (demux->requested_package_string);
5983 demux->requested_package_string = NULL;
5985 g_ptr_array_free (demux->src, TRUE);
5987 g_array_free (demux->essence_tracks, TRUE);
5988 demux->essence_tracks = NULL;
5990 g_hash_table_destroy (demux->metadata);
5992 g_rw_lock_clear (&demux->metadata_lock);
5994 G_OBJECT_CLASS (parent_class)->finalize (object);
5998 gst_mxf_demux_class_init (GstMXFDemuxClass * klass)
6000 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
6001 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
6003 GST_DEBUG_CATEGORY_INIT (mxfdemux_debug, "mxfdemux", 0, "MXF demuxer");
6005 parent_class = g_type_class_peek_parent (klass);
6007 gobject_class->finalize = gst_mxf_demux_finalize;
6008 gobject_class->set_property = gst_mxf_demux_set_property;
6009 gobject_class->get_property = gst_mxf_demux_get_property;
6011 g_object_class_install_property (gobject_class, PROP_PACKAGE,
6012 g_param_spec_string ("package", "Package",
6013 "Material or Source package to use for playback", NULL,
6014 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6016 g_object_class_install_property (gobject_class, PROP_MAX_DRIFT,
6017 g_param_spec_uint64 ("max-drift", "Maximum drift",
6018 "Maximum number of nanoseconds by which tracks can differ",
6019 100 * GST_MSECOND, G_MAXUINT64, DEFAULT_MAX_DRIFT,
6020 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6022 g_object_class_install_property (gobject_class, PROP_STRUCTURE,
6023 g_param_spec_boxed ("structure", "Structure",
6024 "Structural metadata of the MXF file",
6025 GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6027 gstelement_class->change_state =
6028 GST_DEBUG_FUNCPTR (gst_mxf_demux_change_state);
6029 gstelement_class->query = GST_DEBUG_FUNCPTR (gst_mxf_demux_query);
6031 gst_element_class_add_static_pad_template (gstelement_class,
6032 &mxf_sink_template);
6033 gst_element_class_add_static_pad_template (gstelement_class,
6035 gst_element_class_set_static_metadata (gstelement_class, "MXF Demuxer",
6036 "Codec/Demuxer", "Demux MXF files",
6037 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
6041 gst_mxf_demux_init (GstMXFDemux * demux)
6044 gst_pad_new_from_static_template (&mxf_sink_template, "sink");
6046 gst_pad_set_event_function (demux->sinkpad,
6047 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_event));
6048 gst_pad_set_chain_function (demux->sinkpad,
6049 GST_DEBUG_FUNCPTR (gst_mxf_demux_chain));
6050 gst_pad_set_activate_function (demux->sinkpad,
6051 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate));
6052 gst_pad_set_activatemode_function (demux->sinkpad,
6053 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_mode));
6055 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
6057 demux->max_drift = DEFAULT_MAX_DRIFT;
6059 demux->adapter = gst_adapter_new ();
6060 demux->flowcombiner = gst_flow_combiner_new ();
6061 g_rw_lock_init (&demux->metadata_lock);
6063 demux->src = g_ptr_array_new ();
6064 demux->essence_tracks =
6065 g_array_new (FALSE, FALSE, sizeof (GstMXFDemuxEssenceTrack));
6067 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
6069 gst_mxf_demux_reset (demux);