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_essence_track_free (GstMXFDemuxEssenceTrack * t)
176 g_array_free (t->offsets, TRUE);
178 g_free (t->mapping_data);
181 gst_tag_list_unref (t->tags);
184 gst_caps_unref (t->caps);
190 gst_mxf_demux_reset_mxf_state (GstMXFDemux * demux)
192 GST_DEBUG_OBJECT (demux, "Resetting MXF state");
194 g_list_foreach (demux->partitions, (GFunc) gst_mxf_demux_partition_free,
196 g_list_free (demux->partitions);
197 demux->partitions = NULL;
199 demux->current_partition = NULL;
200 g_ptr_array_set_size (demux->essence_tracks, 0);
204 gst_mxf_demux_reset_linked_metadata (GstMXFDemux * demux)
208 for (i = 0; i < demux->src->len; i++) {
209 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
211 pad->material_track = NULL;
212 pad->material_package = NULL;
213 pad->current_component = NULL;
216 for (i = 0; i < demux->essence_tracks->len; i++) {
217 GstMXFDemuxEssenceTrack *track =
218 g_ptr_array_index (demux->essence_tracks, i);
220 track->source_package = NULL;
221 track->delta_id = -1;
222 track->source_track = NULL;
225 demux->current_package = NULL;
229 gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
231 GST_DEBUG_OBJECT (demux, "Resetting metadata");
233 g_rw_lock_writer_lock (&demux->metadata_lock);
235 demux->update_metadata = TRUE;
236 demux->metadata_resolved = FALSE;
238 gst_mxf_demux_reset_linked_metadata (demux);
240 demux->preface = NULL;
242 if (demux->metadata) {
243 g_hash_table_destroy (demux->metadata);
245 demux->metadata = mxf_metadata_hash_table_new ();
248 gst_tag_list_unref (demux->tags);
252 g_rw_lock_writer_unlock (&demux->metadata_lock);
256 gst_mxf_demux_reset (GstMXFDemux * demux)
258 GST_DEBUG_OBJECT (demux, "cleaning up MXF demuxer");
260 demux->flushing = FALSE;
262 demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
264 demux->footer_partition_pack_offset = 0;
267 demux->pull_footer_metadata = TRUE;
271 memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
273 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
275 if (demux->close_seg_event) {
276 gst_event_unref (demux->close_seg_event);
277 demux->close_seg_event = NULL;
280 gst_adapter_clear (demux->adapter);
282 gst_mxf_demux_remove_pads (demux);
284 if (demux->random_index_pack) {
285 g_array_free (demux->random_index_pack, TRUE);
286 demux->random_index_pack = NULL;
289 if (demux->pending_index_table_segments) {
292 for (l = demux->pending_index_table_segments; l; l = l->next) {
293 MXFIndexTableSegment *s = l->data;
294 mxf_index_table_segment_reset (s);
297 g_list_free (demux->pending_index_table_segments);
298 demux->pending_index_table_segments = NULL;
301 if (demux->index_tables) {
304 for (l = demux->index_tables; l; l = l->next) {
305 GstMXFDemuxIndexTable *t = l->data;
306 g_array_free (t->segments, TRUE);
307 g_array_free (t->reverse_temporal_offsets, TRUE);
310 g_list_free (demux->index_tables);
311 demux->index_tables = NULL;
314 demux->index_table_segments_collected = FALSE;
316 gst_mxf_demux_reset_mxf_state (demux);
317 gst_mxf_demux_reset_metadata (demux);
319 demux->have_group_id = FALSE;
320 demux->group_id = G_MAXUINT;
324 gst_mxf_demux_pull_range (GstMXFDemux * demux, guint64 offset,
325 guint size, GstBuffer ** buffer)
329 ret = gst_pad_pull_range (demux->sinkpad, offset, size, buffer);
330 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
331 GST_WARNING_OBJECT (demux,
332 "failed when pulling %u bytes from offset %" G_GUINT64_FORMAT ": %s",
333 size, offset, gst_flow_get_name (ret));
338 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
339 GST_WARNING_OBJECT (demux,
340 "partial pull got %" G_GSIZE_FORMAT " when expecting %u from offset %"
341 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
342 gst_buffer_unref (*buffer);
352 gst_mxf_demux_push_src_event (GstMXFDemux * demux, GstEvent * event)
357 GST_DEBUG_OBJECT (demux, "Pushing '%s' event downstream",
358 GST_EVENT_TYPE_NAME (event));
360 for (i = 0; i < demux->src->len; i++) {
361 GstMXFDemuxPad *pad = GST_MXF_DEMUX_PAD (g_ptr_array_index (demux->src, i));
363 if (pad->eos && GST_EVENT_TYPE (event) == GST_EVENT_EOS)
366 ret |= gst_pad_push_event (GST_PAD_CAST (pad), gst_event_ref (event));
369 gst_event_unref (event);
374 static GstMXFDemuxPad *
375 gst_mxf_demux_get_earliest_pad (GstMXFDemux * demux)
378 GstClockTime earliest = GST_CLOCK_TIME_NONE;
379 GstMXFDemuxPad *pad = NULL;
381 for (i = 0; i < demux->src->len; i++) {
382 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
384 if (!p->eos && p->position < earliest) {
385 earliest = p->position;
394 gst_mxf_demux_partition_compare (GstMXFDemuxPartition * a,
395 GstMXFDemuxPartition * b)
397 if (a->partition.this_partition < b->partition.this_partition)
399 else if (a->partition.this_partition > b->partition.this_partition)
405 /* Final checks and variable calculation for tracks and partition. This function
406 * can be called repeatedly without any side-effect.
409 gst_mxf_demux_partition_postcheck (GstMXFDemux * demux,
410 GstMXFDemuxPartition * partition)
413 GstMXFDemuxPartition *old_partition = demux->current_partition;
415 /* If we already handled this partition or it doesn't contain any essence, skip */
416 if (partition->single_track || !partition->partition.body_sid)
419 for (i = 0; i < demux->essence_tracks->len; i++) {
420 GstMXFDemuxEssenceTrack *cand =
421 g_ptr_array_index (demux->essence_tracks, i);
423 if (cand->body_sid != partition->partition.body_sid)
426 if (!cand->source_package->is_interleaved) {
427 GST_DEBUG_OBJECT (demux,
428 "Assigning single track %d (0x%08x) to partition at offset %"
429 G_GUINT64_FORMAT, cand->track_id, cand->track_number,
430 partition->partition.this_partition);
432 partition->single_track = cand;
434 if (partition->essence_container_offset != 0
435 && cand->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
436 GstMXFKLV essence_klv;
437 GstMXFDemuxIndex entry;
438 /* Update the essence container offset for the fact that the index
439 * stream offset is relative to the essence position and not to the
441 if (gst_mxf_demux_peek_klv_packet (demux,
442 partition->partition.this_partition +
443 partition->essence_container_offset,
444 &essence_klv) == GST_FLOW_OK) {
445 partition->essence_container_offset += essence_klv.data_offset;
446 /* And keep a copy of the clip/custom klv for this partition */
447 partition->clip_klv = essence_klv;
448 GST_DEBUG_OBJECT (demux,
449 "Non-frame wrapping, updated essence_container_offset to %"
450 G_GUINT64_FORMAT, partition->essence_container_offset);
452 /* And match it against index table, this will also update the track delta_id (if needed) */
453 demux->current_partition = partition;
454 find_entry_for_offset (demux, cand,
455 essence_klv.offset + essence_klv.data_offset, &entry);
456 demux->current_partition = old_partition;
466 gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, GstMXFKLV * klv)
468 MXFPartitionPack partition;
470 GstMXFDemuxPartition *p = NULL;
473 GstFlowReturn flowret;
475 GST_DEBUG_OBJECT (demux,
476 "Handling partition pack of size %" G_GSIZE_FORMAT " at offset %"
477 G_GUINT64_FORMAT, klv->length, klv->offset);
479 for (l = demux->partitions; l; l = l->next) {
480 GstMXFDemuxPartition *tmp = l->data;
482 if (tmp->partition.this_partition + demux->run_in == demux->offset &&
483 tmp->partition.major_version == 0x0001) {
484 GST_DEBUG_OBJECT (demux, "Partition already parsed");
490 flowret = gst_mxf_demux_fill_klv (demux, klv);
491 if (flowret != GST_FLOW_OK)
494 gst_buffer_map (klv->data, &map, GST_MAP_READ);
495 ret = mxf_partition_pack_parse (&klv->key, &partition, map.data, map.size);
496 gst_buffer_unmap (klv->data, &map);
498 GST_ERROR_OBJECT (demux, "Parsing partition pack failed");
499 return GST_FLOW_ERROR;
502 if (partition.this_partition != demux->offset + demux->run_in) {
503 GST_WARNING_OBJECT (demux,
504 "Partition with incorrect offset (this %" G_GUINT64_FORMAT
505 " demux offset %" G_GUINT64_FORMAT " run_in:%" G_GUINT64_FORMAT ")",
506 partition.this_partition, demux->offset, demux->run_in);
507 partition.this_partition = demux->offset + demux->run_in;
510 if (partition.type == MXF_PARTITION_PACK_HEADER)
511 demux->footer_partition_pack_offset = partition.footer_partition;
513 for (l = demux->partitions; l; l = l->next) {
514 GstMXFDemuxPartition *tmp = l->data;
516 if (tmp->partition.this_partition + demux->run_in == demux->offset) {
523 mxf_partition_pack_reset (&p->partition);
524 memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
526 p = g_new0 (GstMXFDemuxPartition, 1);
527 memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
529 g_list_insert_sorted (demux->partitions, p,
530 (GCompareFunc) gst_mxf_demux_partition_compare);
533 gst_mxf_demux_partition_postcheck (demux, p);
535 for (l = demux->partitions; l; l = l->next) {
536 GstMXFDemuxPartition *a, *b;
544 b->partition.prev_partition = a->partition.this_partition;
548 GST_DEBUG_OBJECT (demux,
549 "Current partition now %p (body_sid:%d index_sid:%d this_partition:%"
550 G_GUINT64_FORMAT ")", p, p->partition.body_sid, p->partition.index_sid,
551 p->partition.this_partition);
552 demux->current_partition = p;
558 gst_mxf_demux_handle_primer_pack (GstMXFDemux * demux, GstMXFKLV * klv)
562 GstFlowReturn flowret;
564 GST_DEBUG_OBJECT (demux,
565 "Handling primer pack of size %" G_GSIZE_FORMAT " at offset %"
566 G_GUINT64_FORMAT, klv->length, klv->offset);
568 if (G_UNLIKELY (!demux->current_partition)) {
569 GST_ERROR_OBJECT (demux, "Primer pack before partition pack");
570 return GST_FLOW_ERROR;
573 if (G_UNLIKELY (demux->current_partition->primer.mappings)) {
574 GST_DEBUG_OBJECT (demux, "Primer pack already exists");
578 flowret = gst_mxf_demux_fill_klv (demux, klv);
579 if (flowret != GST_FLOW_OK)
582 gst_buffer_map (klv->data, &map, GST_MAP_READ);
583 ret = mxf_primer_pack_parse (&klv->key, &demux->current_partition->primer,
585 gst_buffer_unmap (klv->data, &map);
587 GST_ERROR_OBJECT (demux, "Parsing primer pack failed");
588 return GST_FLOW_ERROR;
591 demux->current_partition->primer.offset = demux->offset;
597 gst_mxf_demux_resolve_references (GstMXFDemux * demux)
599 GstFlowReturn ret = GST_FLOW_OK;
601 MXFMetadataBase *m = NULL;
602 GstStructure *structure;
605 g_rw_lock_writer_lock (&demux->metadata_lock);
607 GST_DEBUG_OBJECT (demux, "Resolve metadata references");
608 demux->update_metadata = FALSE;
610 if (!demux->metadata) {
611 GST_ERROR_OBJECT (demux, "No metadata yet");
612 g_rw_lock_writer_unlock (&demux->metadata_lock);
613 return GST_FLOW_ERROR;
616 g_hash_table_iter_init (&iter, demux->metadata);
617 while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
618 m->resolved = MXF_METADATA_BASE_RESOLVE_STATE_NONE;
621 g_hash_table_iter_init (&iter, demux->metadata);
622 while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
625 resolved = mxf_metadata_base_resolve (m, demux->metadata);
627 /* Resolving can fail for anything but the preface, as the preface
628 * will resolve everything required */
629 if (!resolved && MXF_IS_METADATA_PREFACE (m)) {
630 ret = GST_FLOW_ERROR;
635 demux->metadata_resolved = TRUE;
638 mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
640 demux->tags = gst_tag_list_new_empty ();
642 gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_STRUCTURE,
645 gst_structure_free (structure);
647 /* Check for quirks */
648 for (i = 0; i < demux->preface->n_identifications; i++) {
649 MXFMetadataIdentification *identification =
650 demux->preface->identifications[i];
652 GST_DEBUG_OBJECT (demux, "product:'%s' company:'%s'",
653 identification->product_name, identification->company_name);
654 if (!g_strcmp0 (identification->product_name, "MXFTk Advanced") &&
655 !g_strcmp0 (identification->company_name, "OpenCube") &&
656 identification->product_version.major <= 2 &&
657 identification->product_version.minor <= 0) {
658 GST_WARNING_OBJECT (demux,
659 "Setting up quirk for misuse of temporal_order field");
660 demux->temporal_order_misuse = TRUE;
664 g_rw_lock_writer_unlock (&demux->metadata_lock);
669 demux->metadata_resolved = FALSE;
670 g_rw_lock_writer_unlock (&demux->metadata_lock);
675 static MXFMetadataGenericPackage *
676 gst_mxf_demux_find_package (GstMXFDemux * demux, const MXFUMID * umid)
678 MXFMetadataGenericPackage *ret = NULL;
681 if (demux->preface->content_storage
682 && demux->preface->content_storage->packages) {
683 for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
684 MXFMetadataGenericPackage *p =
685 demux->preface->content_storage->packages[i];
690 if (mxf_umid_is_equal (&p->package_uid, umid)) {
700 static MXFMetadataGenericPackage *
701 gst_mxf_demux_choose_package (GstMXFDemux * demux)
703 MXFMetadataGenericPackage *ret = NULL;
706 if (demux->requested_package_string) {
707 MXFUMID umid = { {0,}
710 if (!mxf_umid_from_string (demux->requested_package_string, &umid)) {
711 GST_ERROR_OBJECT (demux, "Invalid requested package");
713 g_free (demux->requested_package_string);
714 demux->requested_package_string = NULL;
716 ret = gst_mxf_demux_find_package (demux, &umid);
719 if (!ret && !mxf_umid_is_zero (&demux->current_package_uid))
720 ret = gst_mxf_demux_find_package (demux, &demux->current_package_uid);
722 if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
723 || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
724 && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
727 GST_WARNING_OBJECT (demux,
728 "Current package is not a material package or top-level source package, choosing the first best");
729 else if (!mxf_umid_is_zero (&demux->current_package_uid))
730 GST_WARNING_OBJECT (demux,
731 "Current package not found, choosing the first best");
733 ret = demux->preface->primary_package;
734 if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
735 || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
736 && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
740 for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
741 if (demux->preface->content_storage->packages[i] &&
742 MXF_IS_METADATA_MATERIAL_PACKAGE (demux->preface->content_storage->
745 MXF_METADATA_GENERIC_PACKAGE (demux->preface->content_storage->
752 GST_ERROR_OBJECT (demux, "No material package");
757 if (mxf_umid_is_equal (&ret->package_uid, &demux->current_package_uid)) {
758 gchar current_package_string[96];
760 gst_mxf_demux_remove_pads (demux);
761 memcpy (&demux->current_package_uid, &ret->package_uid, 32);
763 mxf_umid_to_string (&ret->package_uid, current_package_string);
764 demux->current_package_string = g_strdup (current_package_string);
765 g_object_notify (G_OBJECT (demux), "package");
768 demux->tags = gst_tag_list_new_empty ();
769 gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_UMID,
770 demux->current_package_string, NULL);
772 demux->current_package = ret;
778 gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux)
782 g_return_val_if_fail (demux->preface->content_storage, GST_FLOW_ERROR);
783 g_return_val_if_fail (demux->preface->content_storage->essence_container_data,
786 for (i = 0; i < demux->preface->content_storage->n_essence_container_data;
788 MXFMetadataEssenceContainerData *edata;
789 MXFMetadataSourcePackage *package;
790 MXFFraction common_rate = { 0, 0 };
792 if (demux->preface->content_storage->essence_container_data[i] == NULL)
795 edata = demux->preface->content_storage->essence_container_data[i];
797 if (!edata->linked_package) {
798 GST_WARNING_OBJECT (demux, "Linked package not resolved");
802 package = edata->linked_package;
804 if (!package->parent.tracks) {
805 GST_WARNING_OBJECT (demux, "Linked package with no resolved tracks");
809 for (j = 0; j < package->parent.n_tracks; j++) {
810 MXFMetadataTimelineTrack *track;
811 GstMXFDemuxEssenceTrack *etrack = NULL;
812 GstCaps *caps = NULL;
813 gboolean new = FALSE;
815 if (!package->parent.tracks[j]
816 || !MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[j])) {
817 GST_DEBUG_OBJECT (demux,
818 "Skipping non-timeline track (id:%d number:0x%08x)",
819 package->parent.tracks[j]->track_id,
820 package->parent.tracks[j]->track_number);
824 track = MXF_METADATA_TIMELINE_TRACK (package->parent.tracks[j]);
825 if ((track->parent.type & 0xf0) != 0x30) {
826 GST_DEBUG_OBJECT (demux,
827 "Skipping track of type 0x%02x (id:%d number:0x%08x)",
828 track->parent.type, track->parent.track_id,
829 track->parent.track_number);
833 if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0) {
834 GST_WARNING_OBJECT (demux, "Invalid edit rate");
838 if (package->is_interleaved) {
840 * S377-1:2019 "9.4.2 The MXF timing model"
842 * The value of Edit Rate shall be identical for every timeline Essence
843 * Track of the Top-Level File Package.
845 * The value of Edit Rate of the timeline Essence Tracks of one
846 * Top-Level File Package need not match the Edit Rate of the Essence
847 * Tracks of the other Top-Level File Packages.
849 * S377-1:2019 "9.5.5 Top-Level File Packages"
851 *12. All Essence Tracks of a Top-Level File Package **shall** have the
852 * same value of Edit Rate. All other Tracks of a Top-Level File
853 * Package **should** have the same value of Edit Rate as the
856 if (common_rate.n == 0 && common_rate.d == 0) {
857 common_rate = track->edit_rate;
858 } else if (common_rate.n * track->edit_rate.d !=
859 common_rate.d * track->edit_rate.n) {
860 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
861 ("Interleaved File Package doesn't have identical edit rate on all tracks."));
862 return GST_FLOW_ERROR;
866 for (k = 0; k < demux->essence_tracks->len; k++) {
867 GstMXFDemuxEssenceTrack *tmp =
868 g_ptr_array_index (demux->essence_tracks, k);
870 if (tmp->track_number == track->parent.track_number &&
871 tmp->body_sid == edata->body_sid) {
872 if (tmp->track_id != track->parent.track_id ||
873 !mxf_umid_is_equal (&tmp->source_package_uid,
874 &package->parent.package_uid)) {
875 GST_ERROR_OBJECT (demux, "There already exists a different track "
876 "with this track number and body sid but a different source "
877 "or source track id -- ignoring");
886 GstMXFDemuxEssenceTrack *tmp = g_new0 (GstMXFDemuxEssenceTrack, 1);
888 tmp->body_sid = edata->body_sid;
889 tmp->index_sid = edata->index_sid;
890 tmp->track_number = track->parent.track_number;
891 tmp->track_id = track->parent.track_id;
892 memcpy (&tmp->source_package_uid, &package->parent.package_uid, 32);
894 if (demux->current_partition->partition.body_sid == edata->body_sid &&
895 demux->current_partition->partition.body_offset == 0)
900 g_ptr_array_add (demux->essence_tracks, tmp);
902 g_ptr_array_index (demux->essence_tracks,
903 demux->essence_tracks->len - 1);
907 etrack->source_package = NULL;
908 etrack->source_track = NULL;
909 etrack->delta_id = -1;
911 if (!track->parent.sequence) {
912 GST_WARNING_OBJECT (demux, "Source track has no sequence");
916 if (track->parent.n_descriptor == 0) {
917 GST_WARNING_OBJECT (demux, "Source track has no descriptors");
921 if (track->parent.sequence->duration > etrack->duration)
922 etrack->duration = track->parent.sequence->duration;
924 g_free (etrack->mapping_data);
925 etrack->mapping_data = NULL;
926 etrack->handler = NULL;
927 etrack->handle_func = NULL;
929 gst_tag_list_unref (etrack->tags);
932 etrack->handler = mxf_essence_element_handler_find (track);
933 if (!etrack->handler) {
934 gchar essence_container[48];
935 gchar essence_compression[48];
938 GST_WARNING_OBJECT (demux,
939 "No essence element handler for track %u found", i);
941 mxf_ul_to_string (&track->parent.descriptor[0]->essence_container,
944 if (track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE) {
945 if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->parent.
947 mxf_ul_to_string (&MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR
948 (track->parent.descriptor[0])->picture_essence_coding,
949 essence_compression);
952 g_strdup_printf ("video/x-mxf-%s-%s", essence_container,
953 essence_compression);
954 } else if (track->parent.type == MXF_METADATA_TRACK_SOUND_ESSENCE) {
955 if (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track->parent.
957 mxf_ul_to_string (&MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR
958 (track->parent.descriptor[0])->sound_essence_compression,
959 essence_compression);
962 g_strdup_printf ("audio/x-mxf-%s-%s", essence_container,
963 essence_compression);
964 } else if (track->parent.type == MXF_METADATA_TRACK_DATA_ESSENCE) {
965 if (MXF_IS_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (track->parent.
967 mxf_ul_to_string (&MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR
968 (track->parent.descriptor[0])->data_essence_coding,
969 essence_compression);
972 g_strdup_printf ("application/x-mxf-%s-%s", essence_container,
973 essence_compression);
976 g_assert_not_reached ();
979 caps = gst_caps_new_empty_simple (name);
981 etrack->intra_only = FALSE;
984 etrack->handler->create_caps (track, &etrack->tags,
985 &etrack->intra_only, &etrack->handle_func, &etrack->mapping_data);
988 GST_DEBUG_OBJECT (demux, "Created caps %" GST_PTR_FORMAT, caps);
991 GST_WARNING_OBJECT (demux, "No caps created, ignoring stream");
992 g_free (etrack->mapping_data);
993 etrack->mapping_data = NULL;
995 gst_tag_list_unref (etrack->tags);
999 GST_WARNING_OBJECT (demux, "Couldn't create updated caps for stream");
1000 } else if (!etrack->caps || !gst_caps_is_equal (etrack->caps, caps)) {
1002 gst_caps_unref (etrack->caps);
1003 etrack->caps = caps;
1005 gst_caps_unref (caps);
1009 etrack->min_edit_units = 1;
1010 /* Ensure we don't output one buffer per sample for audio */
1011 if (gst_util_uint64_scale (GST_SECOND, track->edit_rate.d,
1012 track->edit_rate.n) < 10 * GST_MSECOND) {
1013 GstStructure *s = gst_caps_get_structure (etrack->caps, 0);
1014 const gchar *name = gst_structure_get_name (s);
1015 if (g_str_has_prefix (name, "audio/x-raw")) {
1016 etrack->min_edit_units =
1017 gst_util_uint64_scale (25 * GST_MSECOND, track->edit_rate.n,
1018 track->edit_rate.d * GST_SECOND);
1019 GST_DEBUG_OBJECT (demux, "Seting miminum number of edit units to %u",
1020 etrack->min_edit_units);
1024 /* FIXME : We really should just abort/ignore the stream completely if we
1025 * don't have a handler for it */
1026 if (etrack->handler != NULL)
1027 etrack->wrapping = etrack->handler->get_track_wrapping (track);
1029 etrack->wrapping = MXF_ESSENCE_WRAPPING_UNKNOWN_WRAPPING;
1031 if (package->is_interleaved) {
1032 GST_DEBUG_OBJECT (demux,
1033 "track comes from interleaved source package with %d track(s), setting delta_id to -1",
1034 package->parent.n_tracks);
1035 if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
1036 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1037 ("Non-frame-wrapping is not allowed in interleaved File Package."));
1038 return GST_FLOW_ERROR;
1040 etrack->delta_id = MXF_INDEX_DELTA_ID_UNKNOWN;
1042 etrack->delta_id = MXF_INDEX_DELTA_ID_UNKNOWN;
1044 etrack->source_package = package;
1045 etrack->source_track = track;
1050 g_ptr_array_remove_index (demux->essence_tracks,
1051 demux->essence_tracks->len - 1);
1056 if (demux->essence_tracks->len == 0) {
1057 GST_ERROR_OBJECT (demux, "No valid essence tracks in this file");
1058 return GST_FLOW_ERROR;
1061 for (i = 0; i < demux->essence_tracks->len; i++) {
1062 GstMXFDemuxEssenceTrack *etrack =
1063 g_ptr_array_index (demux->essence_tracks, i);
1065 if (!etrack->source_package || !etrack->source_track || !etrack->caps) {
1066 GST_ERROR_OBJECT (demux, "Failed to update essence track %u", i);
1067 return GST_FLOW_ERROR;
1075 static MXFMetadataEssenceContainerData *
1076 essence_container_for_source_package (MXFMetadataContentStorage * storage,
1077 MXFMetadataSourcePackage * package)
1081 for (i = 0; i < storage->n_essence_container_data; i++) {
1082 MXFMetadataEssenceContainerData *cont = storage->essence_container_data[i];
1083 if (cont && cont->linked_package == package)
1091 gst_mxf_demux_show_topology (GstMXFDemux * demux)
1093 GList *material_packages = NULL;
1094 GList *file_packages = NULL;
1096 MXFMetadataContentStorage *storage = demux->preface->content_storage;
1100 /* Show the topology starting from the preface */
1101 GST_DEBUG_OBJECT (demux, "Topology");
1103 for (i = 0; i < storage->n_packages; i++) {
1104 MXFMetadataGenericPackage *pack = storage->packages[i];
1105 if (MXF_IS_METADATA_MATERIAL_PACKAGE (pack))
1106 material_packages = g_list_append (material_packages, pack);
1107 else if (MXF_IS_METADATA_SOURCE_PACKAGE (pack))
1108 file_packages = g_list_append (file_packages, pack);
1110 GST_DEBUG_OBJECT (demux, "Unknown package type");
1113 GST_DEBUG_OBJECT (demux, "Number of Material Package (i.e. output) : %d",
1114 g_list_length (material_packages));
1115 for (tmp = material_packages; tmp; tmp = tmp->next) {
1116 MXFMetadataMaterialPackage *pack = (MXFMetadataMaterialPackage *) tmp->data;
1117 GST_DEBUG_OBJECT (demux, " Package with %d tracks , UID:%s",
1118 pack->n_tracks, mxf_umid_to_string (&pack->package_uid, str));
1119 for (i = 0; i < pack->n_tracks; i++) {
1120 MXFMetadataTrack *track = pack->tracks[i];
1121 if (track == NULL) {
1122 GST_DEBUG_OBJECT (demux, " Unknown/Unhandled track UUID %s",
1123 mxf_uuid_to_string (&pack->tracks_uids[i], str));
1124 } else if (MXF_IS_METADATA_TIMELINE_TRACK (track)) {
1125 MXFMetadataTimelineTrack *mtrack = (MXFMetadataTimelineTrack *) track;
1126 GST_DEBUG_OBJECT (demux,
1127 " Timeline Track id:%d number:0x%08x name:`%s` edit_rate:%d/%d origin:%"
1128 G_GINT64_FORMAT, track->track_id, track->track_number,
1129 track->track_name, mtrack->edit_rate.n, mtrack->edit_rate.d,
1132 GST_DEBUG_OBJECT (demux,
1133 " Non-Timeline-Track id:%d number:0x%08x name:`%s`",
1134 track->track_id, track->track_number, track->track_name);
1137 MXFMetadataSequence *sequence = track->sequence;
1139 GST_DEBUG_OBJECT (demux,
1140 " Sequence duration:%" G_GINT64_FORMAT
1141 " n_structural_components:%d", sequence->duration,
1142 sequence->n_structural_components);
1143 for (si = 0; si < sequence->n_structural_components; si++) {
1144 MXFMetadataStructuralComponent *comp =
1145 sequence->structural_components[si];
1146 GST_DEBUG_OBJECT (demux,
1147 " Component #%d duration:%" G_GINT64_FORMAT, si,
1149 if (MXF_IS_METADATA_SOURCE_CLIP (comp)) {
1150 MXFMetadataSourceClip *clip = (MXFMetadataSourceClip *) comp;
1151 GST_DEBUG_OBJECT (demux,
1152 " Clip start_position:%" G_GINT64_FORMAT
1153 " source_track_id:%d source_package_id:%s",
1154 clip->start_position, clip->source_track_id,
1155 mxf_umid_to_string (&clip->source_package_id, str));
1163 GST_DEBUG_OBJECT (demux, "Number of File Packages (i.e. input) : %d",
1164 g_list_length (file_packages));
1165 for (tmp = file_packages; tmp; tmp = tmp->next) {
1166 MXFMetadataMaterialPackage *pack = (MXFMetadataMaterialPackage *) tmp->data;
1167 MXFMetadataSourcePackage *src = (MXFMetadataSourcePackage *) pack;
1168 MXFMetadataEssenceContainerData *econt =
1169 essence_container_for_source_package (storage, src);
1170 GST_DEBUG_OBJECT (demux,
1171 " Package (body_sid:%d index_sid:%d top_level:%d) with %d tracks , UID:%s",
1172 econt->body_sid, econt->index_sid, src->top_level, pack->n_tracks,
1173 mxf_umid_to_string (&pack->package_uid, str));
1174 GST_DEBUG_OBJECT (demux, " Package descriptor : %s",
1175 g_type_name (G_OBJECT_TYPE (src->descriptor)));
1176 for (i = 0; i < pack->n_tracks; i++) {
1177 MXFMetadataTrack *track = pack->tracks[i];
1178 MXFMetadataSequence *sequence = track->sequence;
1180 if (MXF_IS_METADATA_TIMELINE_TRACK (track)) {
1181 MXFMetadataTimelineTrack *mtrack = (MXFMetadataTimelineTrack *) track;
1182 GST_DEBUG_OBJECT (demux,
1183 " Timeline Track id:%d number:0x%08x name:`%s` edit_rate:%d/%d origin:%"
1184 G_GINT64_FORMAT, track->track_id, track->track_number,
1185 track->track_name, mtrack->edit_rate.n, mtrack->edit_rate.d,
1188 GST_DEBUG_OBJECT (demux,
1189 " Non-Timeline-Track id:%d number:0x%08x name:`%s` type:0x%x",
1190 track->track_id, track->track_number, track->track_name,
1193 for (di = 0; di < track->n_descriptor; di++) {
1194 MXFMetadataFileDescriptor *desc = track->descriptor[di];
1195 GST_DEBUG_OBJECT (demux, " Descriptor %s %s",
1196 g_type_name (G_OBJECT_TYPE (desc)),
1197 mxf_ul_to_string (&desc->essence_container, str));
1199 GST_DEBUG_OBJECT (demux,
1200 " Sequence duration:%" G_GINT64_FORMAT
1201 " n_structural_components:%d", sequence->duration,
1202 sequence->n_structural_components);
1203 for (si = 0; si < sequence->n_structural_components; si++) {
1204 MXFMetadataStructuralComponent *comp =
1205 sequence->structural_components[si];
1206 GST_DEBUG_OBJECT (demux,
1207 " Component #%d duration:%" G_GINT64_FORMAT, si,
1213 g_list_free (material_packages);
1214 g_list_free (file_packages);
1217 static GstFlowReturn
1218 gst_mxf_demux_update_tracks (GstMXFDemux * demux)
1220 MXFMetadataGenericPackage *current_package = NULL;
1223 guint component_index;
1225 GList *pads = NULL, *l;
1226 GstVideoTimeCode start_timecode = GST_VIDEO_TIME_CODE_INIT;
1228 g_rw_lock_writer_lock (&demux->metadata_lock);
1229 GST_DEBUG_OBJECT (demux, "Updating tracks");
1231 gst_mxf_demux_show_topology (demux);
1233 if ((ret = gst_mxf_demux_update_essence_tracks (demux)) != GST_FLOW_OK) {
1237 current_package = gst_mxf_demux_choose_package (demux);
1239 if (!current_package) {
1240 GST_ERROR_OBJECT (demux, "Unable to find current package");
1241 ret = GST_FLOW_ERROR;
1243 } else if (!current_package->tracks) {
1244 GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks");
1245 ret = GST_FLOW_ERROR;
1247 } else if (!current_package->n_essence_tracks) {
1248 GST_ERROR_OBJECT (demux, "Current package has no essence tracks");
1249 ret = GST_FLOW_ERROR;
1253 first_run = (demux->src->len == 0);
1255 /* For material packages, there must be one timecode track with one
1256 * continuous timecode. For source packages there might be multiple,
1257 * discontinuous timecode components.
1258 * TODO: Support multiple timecode components
1260 for (i = 0; i < current_package->n_tracks; i++) {
1261 MXFMetadataTimelineTrack *track = NULL;
1262 MXFMetadataSequence *sequence = NULL;
1263 MXFMetadataTimecodeComponent *component = NULL;
1265 if (!current_package->tracks[i]) {
1266 GST_WARNING_OBJECT (demux, "Unresolved track");
1270 if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
1271 GST_DEBUG_OBJECT (demux, "Skipping Non-timeline track");
1276 track = MXF_METADATA_TIMELINE_TRACK (current_package->tracks[i]);
1278 if (!track->parent.sequence)
1280 sequence = track->parent.sequence;
1281 if (sequence->n_structural_components != 1 ||
1282 !sequence->structural_components[0]
1284 !MXF_IS_METADATA_TIMECODE_COMPONENT (sequence->structural_components
1289 MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1291 /* Not a timecode track */
1292 if (track->parent.type && (track->parent.type & 0xf0) != 0x10)
1295 /* Main timecode track must have id 1, all others must be 0 */
1296 if (track->parent.track_id != 1)
1299 gst_video_time_code_init (&start_timecode, track->edit_rate.n,
1300 track->edit_rate.d, NULL, (component->drop_frame
1302 GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME
1303 : GST_VIDEO_TIME_CODE_FLAGS_NONE), 0, 0, 0, 0, 0);
1304 gst_video_time_code_add_frames (&start_timecode, track->origin);
1305 gst_video_time_code_add_frames (&start_timecode, component->start_timecode);
1309 for (i = 0; i < current_package->n_tracks; i++) {
1310 MXFMetadataTimelineTrack *track = NULL;
1311 MXFMetadataSequence *sequence;
1312 MXFMetadataSourceClip *component = NULL;
1313 MXFMetadataSourcePackage *source_package = NULL;
1314 MXFMetadataTimelineTrack *source_track = NULL;
1315 GstMXFDemuxEssenceTrack *etrack = NULL;
1316 GstMXFDemuxPad *pad = NULL;
1319 GST_DEBUG_OBJECT (demux, "Handling track %u", i);
1321 if (!current_package->tracks[i]) {
1322 GST_WARNING_OBJECT (demux, "Unresolved track");
1326 if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
1327 GST_DEBUG_OBJECT (demux, "No timeline track");
1331 track = MXF_METADATA_TIMELINE_TRACK (current_package->tracks[i]);
1334 /* Find pad from track_id */
1335 for (j = 0; j < demux->src->len; j++) {
1336 GstMXFDemuxPad *tmp = g_ptr_array_index (demux->src, j);
1338 if (tmp->track_id == track->parent.track_id) {
1346 component_index = pad->current_component_index;
1348 component_index = 0;
1350 if (!track->parent.sequence) {
1351 GST_WARNING_OBJECT (demux, "Track with no sequence");
1355 ret = GST_FLOW_ERROR;
1360 sequence = track->parent.sequence;
1362 if (MXF_IS_METADATA_SOURCE_PACKAGE (current_package)) {
1363 GST_DEBUG_OBJECT (demux, "Playing source package");
1366 source_package = MXF_METADATA_SOURCE_PACKAGE (current_package);
1367 source_track = track;
1368 } else if (sequence->structural_components
1370 MXF_IS_METADATA_SOURCE_CLIP (sequence->structural_components
1371 [component_index])) {
1372 GST_DEBUG_OBJECT (demux, "Playing material package");
1375 MXF_METADATA_SOURCE_CLIP (sequence->structural_components
1378 GST_WARNING_OBJECT (demux, "NULL component in non-source package");
1382 ret = GST_FLOW_ERROR;
1387 if (component->source_package && component->source_package->top_level &&
1388 MXF_METADATA_GENERIC_PACKAGE (component->source_package)->tracks) {
1389 MXFMetadataGenericPackage *tmp_pkg =
1390 MXF_METADATA_GENERIC_PACKAGE (component->source_package);
1392 source_package = component->source_package;
1394 for (k = 0; k < tmp_pkg->n_tracks; k++) {
1395 MXFMetadataTrack *tmp = tmp_pkg->tracks[k];
1397 if (tmp->track_id == component->source_track_id) {
1398 source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1405 if (track->parent.type && (track->parent.type & 0xf0) != 0x30) {
1406 GST_DEBUG_OBJECT (demux,
1407 "No essence track. type:0x%02x track_id:%d track_number:0x%08x",
1408 track->parent.type, track->parent.track_id,
1409 track->parent.track_number);
1413 ret = GST_FLOW_ERROR;
1418 if (!source_package || track->parent.type == MXF_METADATA_TRACK_UNKNOWN
1420 GST_WARNING_OBJECT (demux,
1421 "No source package or track type for track found");
1425 ret = GST_FLOW_ERROR;
1430 for (k = 0; k < demux->essence_tracks->len; k++) {
1431 GstMXFDemuxEssenceTrack *tmp =
1432 g_ptr_array_index (demux->essence_tracks, k);
1434 if (tmp->source_package == source_package &&
1435 tmp->source_track == source_track) {
1442 GST_WARNING_OBJECT (demux, "No essence track for this track found");
1446 ret = GST_FLOW_ERROR;
1451 if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0 ||
1452 source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1453 GST_WARNING_OBJECT (demux, "Track has an invalid edit rate");
1457 ret = GST_FLOW_ERROR;
1462 if (MXF_IS_METADATA_MATERIAL_PACKAGE (current_package) && !component) {
1463 GST_WARNING_OBJECT (demux,
1464 "Playing material package but found no component for track");
1468 ret = GST_FLOW_ERROR;
1473 if (!source_package->descriptor) {
1474 GST_WARNING_OBJECT (demux, "Source package has no descriptors");
1478 ret = GST_FLOW_ERROR;
1483 if (!source_track->parent.descriptor) {
1484 GST_WARNING_OBJECT (demux, "No descriptor found for track");
1488 ret = GST_FLOW_ERROR;
1493 if (!pad && first_run) {
1494 GstPadTemplate *templ;
1498 gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
1500 pad_name = g_strdup_printf ("track_%u", track->parent.track_id);
1502 g_assert (templ != NULL);
1505 pad = (GstMXFDemuxPad *) g_object_new (GST_TYPE_MXF_DEMUX_PAD,
1506 "name", pad_name, "direction", GST_PAD_SRC, "template", templ, NULL);
1507 pad->need_segment = TRUE;
1512 pad->tags = gst_tag_list_copy (demux->tags);
1516 GST_WARNING_OBJECT (demux,
1517 "Not the first pad addition run, ignoring new track");
1522 pad->track_id = track->parent.track_id;
1524 pad->material_package = current_package;
1525 pad->material_track = track;
1527 pad->start_timecode = start_timecode;
1529 /* If we just added the pad initialize for the current component */
1530 if (first_run && MXF_IS_METADATA_MATERIAL_PACKAGE (current_package)) {
1531 pad->current_component_index = 0;
1532 pad->current_component_start = source_track->origin;
1533 pad->current_component_start_position = 0;
1535 if (component->parent.duration >= -1)
1536 pad->current_component_duration = component->parent.duration;
1538 pad->current_component_duration = -1;
1540 if (track->edit_rate.n != source_track->edit_rate.n ||
1541 track->edit_rate.d != source_track->edit_rate.d) {
1542 pad->current_component_start +=
1543 gst_util_uint64_scale (component->start_position,
1544 source_track->edit_rate.n * track->edit_rate.d,
1545 source_track->edit_rate.d * track->edit_rate.n);
1547 if (pad->current_component_duration != -1)
1548 pad->current_component_duration =
1549 gst_util_uint64_scale (pad->current_component_duration,
1550 source_track->edit_rate.n * track->edit_rate.d,
1551 source_track->edit_rate.d * track->edit_rate.n);
1553 pad->current_component_start += component->start_position;
1555 pad->current_essence_track_position = pad->current_component_start;
1558 /* NULL iff playing a source package */
1559 pad->current_component = component;
1561 pad->current_essence_track = etrack;
1565 gst_tag_list_insert (pad->tags, etrack->tags, GST_TAG_MERGE_REPLACE);
1567 pad->tags = gst_tag_list_copy (etrack->tags);
1570 pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1571 if (pad_caps && !gst_caps_is_equal (pad_caps, etrack->caps)) {
1572 gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1573 } else if (!pad_caps) {
1577 gst_pad_set_event_function (GST_PAD_CAST (pad),
1578 GST_DEBUG_FUNCPTR (gst_mxf_demux_src_event));
1580 gst_pad_set_query_function (GST_PAD_CAST (pad),
1581 GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query));
1583 gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
1584 gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
1587 gst_pad_create_stream_id_printf (GST_PAD_CAST (pad),
1588 GST_ELEMENT_CAST (demux), "%03u", pad->track_id);
1591 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
1593 if (gst_event_parse_group_id (event, &demux->group_id))
1594 demux->have_group_id = TRUE;
1596 demux->have_group_id = FALSE;
1597 gst_event_unref (event);
1598 } else if (!demux->have_group_id) {
1599 demux->have_group_id = TRUE;
1600 demux->group_id = gst_util_group_id_next ();
1602 event = gst_event_new_stream_start (stream_id);
1603 if (demux->have_group_id)
1604 gst_event_set_group_id (event, demux->group_id);
1606 gst_pad_push_event (GST_PAD_CAST (pad), event);
1609 gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1611 pads = g_list_prepend (pads, gst_object_ref (pad));
1613 g_ptr_array_add (demux->src, pad);
1614 pad->discont = TRUE;
1617 gst_caps_unref (pad_caps);
1620 if (demux->src->len > 0) {
1621 for (i = 0; i < demux->src->len; i++) {
1622 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
1624 if (!pad->material_track || !pad->material_package) {
1625 GST_ERROR_OBJECT (demux, "Unable to update existing pad");
1626 ret = GST_FLOW_ERROR;
1631 GST_ERROR_OBJECT (demux, "Couldn't create any streams");
1632 ret = GST_FLOW_ERROR;
1636 g_rw_lock_writer_unlock (&demux->metadata_lock);
1638 for (l = pads; l; l = l->next) {
1639 gst_flow_combiner_add_pad (demux->flowcombiner, l->data);
1640 gst_element_add_pad (GST_ELEMENT_CAST (demux), l->data);
1645 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1647 /* Re-check all existing partitions for source package linking in case the
1648 * header partition contains data (allowed in early MXF versions) */
1649 for (l = demux->partitions; l; l = l->next)
1650 gst_mxf_demux_partition_postcheck (demux, (GstMXFDemuxPartition *) l->data);
1655 g_rw_lock_writer_unlock (&demux->metadata_lock);
1659 static GstFlowReturn
1660 gst_mxf_demux_handle_metadata (GstMXFDemux * demux, GstMXFKLV * klv)
1663 MXFMetadata *metadata = NULL, *old = NULL;
1665 GstFlowReturn ret = GST_FLOW_OK;
1667 type = GST_READ_UINT16_BE (&klv->key.u[13]);
1669 GST_DEBUG_OBJECT (demux,
1670 "Handling metadata of size %" G_GSIZE_FORMAT " at offset %"
1671 G_GUINT64_FORMAT " of type 0x%04x", klv->length, klv->offset, type);
1673 if (G_UNLIKELY (!demux->current_partition)) {
1674 GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1675 return GST_FLOW_ERROR;
1678 if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1679 GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1680 return GST_FLOW_ERROR;
1683 if (demux->current_partition->parsed_metadata) {
1684 GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1688 if (klv->length == 0)
1690 ret = gst_mxf_demux_fill_klv (demux, klv);
1691 if (ret != GST_FLOW_OK)
1694 gst_buffer_map (klv->data, &map, GST_MAP_READ);
1696 mxf_metadata_new (type, &demux->current_partition->primer, demux->offset,
1697 map.data, map.size);
1698 gst_buffer_unmap (klv->data, &map);
1701 GST_WARNING_OBJECT (demux,
1702 "Unknown or unhandled metadata of type 0x%04x", type);
1707 g_hash_table_lookup (demux->metadata,
1708 &MXF_METADATA_BASE (metadata)->instance_uid);
1710 if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (metadata)) {
1711 #ifndef GST_DISABLE_GST_DEBUG
1715 GST_DEBUG_OBJECT (demux,
1716 "Metadata with instance uid %s already exists and has different type '%s',"
1718 mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str),
1719 g_type_name (G_TYPE_FROM_INSTANCE (old)),
1720 g_type_name (G_TYPE_FROM_INSTANCE (metadata)));
1721 g_object_unref (metadata);
1722 return GST_FLOW_ERROR;
1724 && MXF_METADATA_BASE (old)->offset >=
1725 MXF_METADATA_BASE (metadata)->offset) {
1726 #ifndef GST_DISABLE_GST_DEBUG
1730 GST_DEBUG_OBJECT (demux,
1731 "Metadata with instance uid %s already exists and is newer",
1732 mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str));
1733 g_object_unref (metadata);
1737 g_rw_lock_writer_lock (&demux->metadata_lock);
1738 demux->update_metadata = TRUE;
1740 if (MXF_IS_METADATA_PREFACE (metadata)) {
1741 demux->preface = MXF_METADATA_PREFACE (metadata);
1744 gst_mxf_demux_reset_linked_metadata (demux);
1746 g_hash_table_replace (demux->metadata,
1747 &MXF_METADATA_BASE (metadata)->instance_uid, metadata);
1748 g_rw_lock_writer_unlock (&demux->metadata_lock);
1753 static GstFlowReturn
1754 gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux, GstMXFKLV * klv)
1759 GstFlowReturn ret = GST_FLOW_OK;
1760 MXFDescriptiveMetadata *m = NULL, *old = NULL;
1762 scheme = GST_READ_UINT8 (&klv->key.u[12]);
1763 type = GST_READ_UINT24_BE (&klv->key.u[13]);
1765 GST_DEBUG_OBJECT (demux,
1766 "Handling descriptive metadata of size %" G_GSIZE_FORMAT " at offset %"
1767 G_GUINT64_FORMAT " with scheme 0x%02x and type 0x%06x",
1768 klv->length, klv->offset, scheme, type);
1770 if (G_UNLIKELY (!demux->current_partition)) {
1771 GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1772 return GST_FLOW_ERROR;
1775 if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1776 GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1777 return GST_FLOW_ERROR;
1780 if (demux->current_partition->parsed_metadata) {
1781 GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1785 ret = gst_mxf_demux_fill_klv (demux, klv);
1786 if (ret != GST_FLOW_OK)
1789 gst_buffer_map (klv->data, &map, GST_MAP_READ);
1790 m = mxf_descriptive_metadata_new (scheme, type,
1791 &demux->current_partition->primer, demux->offset, map.data, map.size);
1792 gst_buffer_unmap (klv->data, &map);
1795 GST_WARNING_OBJECT (demux,
1796 "Unknown or unhandled descriptive metadata of scheme 0x%02x and type 0x%06x",
1802 g_hash_table_lookup (demux->metadata,
1803 &MXF_METADATA_BASE (m)->instance_uid);
1805 if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (m)) {
1806 #ifndef GST_DISABLE_GST_DEBUG
1810 GST_DEBUG_OBJECT (demux,
1811 "Metadata with instance uid %s already exists and has different type '%s',"
1813 mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str),
1814 g_type_name (G_TYPE_FROM_INSTANCE (old)),
1815 g_type_name (G_TYPE_FROM_INSTANCE (m)));
1817 return GST_FLOW_ERROR;
1819 && MXF_METADATA_BASE (old)->offset >= MXF_METADATA_BASE (m)->offset) {
1820 #ifndef GST_DISABLE_GST_DEBUG
1824 GST_DEBUG_OBJECT (demux,
1825 "Metadata with instance uid %s already exists and is newer",
1826 mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str));
1831 g_rw_lock_writer_lock (&demux->metadata_lock);
1833 demux->update_metadata = TRUE;
1834 gst_mxf_demux_reset_linked_metadata (demux);
1836 g_hash_table_replace (demux->metadata, &MXF_METADATA_BASE (m)->instance_uid,
1839 g_rw_lock_writer_unlock (&demux->metadata_lock);
1844 static GstFlowReturn
1845 gst_mxf_demux_handle_generic_container_system_item (GstMXFDemux * demux,
1848 GST_DEBUG_OBJECT (demux,
1849 "Handling generic container system item of size %" G_GSIZE_FORMAT
1850 " at offset %" G_GUINT64_FORMAT, klv->length, klv->offset);
1852 if (demux->current_partition->essence_container_offset == 0)
1853 demux->current_partition->essence_container_offset =
1854 demux->offset - demux->current_partition->partition.this_partition -
1857 /* TODO: parse this */
1861 static GstFlowReturn
1862 gst_mxf_demux_pad_set_component (GstMXFDemux * demux, GstMXFDemuxPad * pad,
1865 GstFlowReturn ret = GST_FLOW_OK;
1867 MXFMetadataSequence *sequence;
1869 MXFMetadataSourcePackage *source_package = NULL;
1870 MXFMetadataTimelineTrack *source_track = NULL;
1871 gboolean update = (pad->current_component_index != i);
1873 pad->current_component_index = i;
1875 sequence = pad->material_track->parent.sequence;
1877 if (pad->current_component_index >= sequence->n_structural_components) {
1878 GST_DEBUG_OBJECT (demux, "After last structural component");
1879 pad->current_component_index = sequence->n_structural_components - 1;
1883 GST_DEBUG_OBJECT (demux, "Switching to component %u",
1884 pad->current_component_index);
1886 pad->current_component =
1887 MXF_METADATA_SOURCE_CLIP (sequence->structural_components[pad->
1888 current_component_index]);
1889 if (pad->current_component == NULL) {
1890 GST_ERROR_OBJECT (demux, "No such structural component");
1891 return GST_FLOW_ERROR;
1894 if (!pad->current_component->source_package
1895 || !pad->current_component->source_package->top_level
1896 || !MXF_METADATA_GENERIC_PACKAGE (pad->current_component->
1897 source_package)->tracks) {
1898 GST_ERROR_OBJECT (demux, "Invalid component");
1899 return GST_FLOW_ERROR;
1902 source_package = pad->current_component->source_package;
1904 for (k = 0; k < source_package->parent.n_tracks; k++) {
1905 MXFMetadataTrack *tmp = source_package->parent.tracks[k];
1907 if (tmp->track_id == pad->current_component->source_track_id) {
1908 source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1913 if (!source_track) {
1914 GST_ERROR_OBJECT (demux, "No source track found");
1915 return GST_FLOW_ERROR;
1918 pad->current_essence_track = NULL;
1920 for (k = 0; k < demux->essence_tracks->len; k++) {
1921 GstMXFDemuxEssenceTrack *tmp = g_ptr_array_index (demux->essence_tracks, k);
1923 if (tmp->source_package == source_package &&
1924 tmp->source_track == source_track) {
1925 pad->current_essence_track = tmp;
1930 if (!pad->current_essence_track) {
1931 GST_ERROR_OBJECT (demux, "No corresponding essence track found");
1932 return GST_FLOW_ERROR;
1935 if (!source_package->descriptor) {
1936 GST_ERROR_OBJECT (demux, "Source package has no descriptors");
1937 return GST_FLOW_ERROR;
1940 if (!source_track->parent.descriptor) {
1941 GST_ERROR_OBJECT (demux, "No descriptor found for track");
1942 return GST_FLOW_ERROR;
1945 if (source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1946 GST_ERROR_OBJECT (demux, "Source track has invalid edit rate");
1947 return GST_FLOW_ERROR;
1950 pad->current_component_start_position = 0;
1951 for (k = 0; k < i; k++) {
1952 pad->current_component_start_position +=
1953 MXF_METADATA_SOURCE_CLIP (sequence->structural_components[k])->
1957 if (pad->current_component->parent.duration >= -1)
1958 pad->current_component_duration = pad->current_component->parent.duration;
1960 pad->current_component_duration = -1;
1962 if (pad->material_track->edit_rate.n != source_track->edit_rate.n ||
1963 pad->material_track->edit_rate.d != source_track->edit_rate.d) {
1964 pad->current_component_start +=
1965 gst_util_uint64_scale (pad->current_component->start_position,
1966 source_track->edit_rate.n * pad->material_track->edit_rate.d,
1967 source_track->edit_rate.d * pad->material_track->edit_rate.n);
1969 if (pad->current_component_duration != -1)
1970 pad->current_component_duration =
1971 gst_util_uint64_scale (pad->current_component_duration,
1972 source_track->edit_rate.n * pad->material_track->edit_rate.d,
1973 source_track->edit_rate.d * pad->material_track->edit_rate.n);
1975 pad->current_component_start += pad->current_component->start_position;
1977 pad->current_essence_track_position = pad->current_component_start;
1979 pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1981 || !gst_caps_is_equal (pad_caps, pad->current_essence_track->caps)) {
1982 gst_pad_set_caps (GST_PAD_CAST (pad), pad->current_essence_track->caps);
1985 gst_caps_unref (pad_caps);
1989 if (pad->current_essence_track->tags)
1990 gst_tag_list_insert (pad->tags, pad->current_essence_track->tags,
1991 GST_TAG_MERGE_REPLACE);
1993 if (pad->current_essence_track->tags)
1994 pad->tags = gst_tag_list_copy (pad->current_essence_track->tags);
1998 if (ret == GST_FLOW_EOS) {
1999 pad->current_essence_track_position += pad->current_component_duration;
2006 * Find the partition containing the stream offset of the given track
2008 static GstMXFDemuxPartition *
2009 get_partition_for_stream_offset (GstMXFDemux * demux,
2010 GstMXFDemuxEssenceTrack * etrack, guint64 stream_offset)
2013 GstMXFDemuxPartition *offset_partition = NULL, *next_partition = NULL;
2015 for (tmp = demux->partitions; tmp; tmp = tmp->next) {
2016 GstMXFDemuxPartition *partition = tmp->data;
2018 if (!next_partition && offset_partition)
2019 next_partition = partition;
2021 if (partition->partition.body_sid != etrack->body_sid)
2023 if (partition->partition.body_offset > stream_offset)
2026 offset_partition = partition;
2027 next_partition = NULL;
2030 if (offset_partition
2031 && stream_offset < offset_partition->partition.body_offset)
2034 GST_DEBUG_OBJECT (demux,
2035 "Found this_partition:%" G_GUINT64_FORMAT " body_offset:%"
2036 G_GUINT64_FORMAT, offset_partition->partition.this_partition,
2037 offset_partition->partition.body_offset);
2039 /* Are we overriding into the next partition ? */
2040 if (next_partition) {
2041 guint64 partition_essence_size =
2042 next_partition->partition.this_partition -
2043 offset_partition->partition.this_partition +
2044 offset_partition->essence_container_offset;
2045 guint64 in_partition =
2046 stream_offset - offset_partition->partition.body_offset;
2047 GST_DEBUG_OBJECT (demux,
2048 "Followed by this_partition:%" G_GUINT64_FORMAT " body_offset:%"
2049 G_GUINT64_FORMAT, next_partition->partition.this_partition,
2050 next_partition->partition.body_offset);
2052 if (in_partition >= partition_essence_size) {
2053 GST_WARNING_OBJECT (demux,
2054 "stream_offset %" G_GUINT64_FORMAT
2055 " in track body_sid:% index_sid:%d leaks into next unrelated partition (body_sid:%d / index_sid:%d)",
2056 stream_offset, etrack->body_sid, etrack->index_sid,
2057 next_partition->partition.body_sid,
2058 next_partition->partition.index_sid);
2062 return offset_partition;
2065 static GstMXFDemuxIndexTable *
2066 get_track_index_table (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack)
2070 /* Look in the indextables */
2071 for (l = demux->index_tables; l; l = l->next) {
2072 GstMXFDemuxIndexTable *tmp = l->data;
2074 if (tmp->body_sid == etrack->body_sid
2075 && tmp->index_sid == etrack->index_sid) {
2084 get_track_max_temporal_offset (GstMXFDemux * demux,
2085 GstMXFDemuxEssenceTrack * etrack)
2087 GstMXFDemuxIndexTable *table;
2089 if (etrack->intra_only)
2092 table = get_track_index_table (demux, etrack);
2095 return table->max_temporal_offset;
2100 find_offset (GArray * offsets, gint64 * position, gboolean keyframe)
2102 GstMXFDemuxIndex *idx;
2103 guint64 current_offset = -1;
2104 gint64 current_position = *position;
2106 if (!offsets || offsets->len <= *position)
2109 idx = &g_array_index (offsets, GstMXFDemuxIndex, *position);
2110 if (idx->offset != 0 && (!keyframe || idx->keyframe)) {
2111 current_offset = idx->offset;
2112 } else if (idx->offset != 0) {
2114 while (current_position >= 0) {
2115 GST_LOG ("current_position %" G_GINT64_FORMAT, current_position);
2116 idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
2117 if (idx->offset == 0) {
2118 GST_LOG ("breaking offset 0");
2120 } else if (!idx->keyframe) {
2124 GST_LOG ("Breaking found offset");
2125 current_offset = idx->offset;
2131 if (current_offset == -1)
2134 *position = current_position;
2135 return current_offset;
2140 * @demux: The demuxer
2141 * @etrack: The target essence track
2142 * @position: An edit unit position
2143 * @keyframe: if TRUE search for supporting keyframe
2144 * @entry: (out): Will be filled with the matching entry information
2146 * Finds the edit entry of @etrack for the given edit unit @position and fill
2147 * @entry with the information about that edit entry. If @keyframe is TRUE, the
2148 * supporting entry (i.e. keyframe) for the given position will be searched for.
2150 * For frame-wrapped contents, the returned offset will be the position of the
2151 * KLV of the content. For clip-wrapped content, the returned offset will be the
2152 * position of the essence (i.e. without KLV header) and the entry will specify
2153 * the size (in bytes).
2155 * The returned entry will also specify the duration (in edit units) of the
2156 * content, which can be different from 1 for special cases (such as raw audio
2157 * where multiple samples could be aggregated).
2159 * Returns: TRUE if the entry was found and @entry was properly filled, else
2163 find_edit_entry (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack,
2164 gint64 position, gboolean keyframe, GstMXFDemuxIndex * entry)
2166 GstMXFDemuxIndexTable *index_table = NULL;
2168 MXFIndexTableSegment *segment = NULL;
2169 GstMXFDemuxPartition *offset_partition = NULL;
2170 guint64 stream_offset = G_MAXUINT64, absolute_offset;
2172 GST_DEBUG_OBJECT (demux,
2173 "track %d body_sid:%d index_sid:%d delta_id:%d position:%" G_GINT64_FORMAT
2174 " keyframe:%d", etrack->track_id, etrack->body_sid,
2175 etrack->index_sid, etrack->delta_id, position, keyframe);
2177 /* Default values */
2178 entry->duration = 1;
2179 /* By default every entry is a keyframe unless specified otherwise */
2180 entry->keyframe = TRUE;
2182 /* Look in the track offsets */
2183 if (etrack->offsets && etrack->offsets->len > position) {
2184 if (find_offset (etrack->offsets, &position, keyframe) != -1) {
2185 *entry = g_array_index (etrack->offsets, GstMXFDemuxIndex, position);
2186 GST_LOG_OBJECT (demux, "Found entry in track offsets");
2189 GST_LOG_OBJECT (demux, "Didn't find entry in track offsets");
2192 /* Look in the indextables */
2193 index_table = get_track_index_table (demux, etrack);
2196 GST_DEBUG_OBJECT (demux,
2197 "Couldn't find index table for body_sid:%d index_sid:%d",
2198 etrack->body_sid, etrack->index_sid);
2202 GST_DEBUG_OBJECT (demux,
2203 "Looking for position %" G_GINT64_FORMAT
2204 " in index table (max temporal offset %u)",
2205 etrack->position, index_table->max_temporal_offset);
2207 /* Searching for a position in index tables works in 3 steps:
2209 * 1. Figure out the table segment containing that position
2210 * 2. Figure out the "stream offset" (and additional flags/timing) of that
2211 * position from the table segment.
2212 * 3. Figure out the "absolute offset" of that "stream offset" using partitions
2217 /* Find matching index segment */
2218 GST_DEBUG_OBJECT (demux, "Look for entry in %d segments",
2219 index_table->segments->len);
2220 for (i = 0; i < index_table->segments->len; i++) {
2221 MXFIndexTableSegment *cand =
2222 &g_array_index (index_table->segments, MXFIndexTableSegment, i);
2223 if (position >= cand->index_start_position && (cand->index_duration == 0
2225 (cand->index_start_position + cand->index_duration))) {
2226 GST_DEBUG_OBJECT (demux,
2227 "Entry is in Segment #%d , start: %" G_GINT64_FORMAT " , duration: %"
2228 G_GINT64_FORMAT, i, cand->index_start_position, cand->index_duration);
2234 GST_DEBUG_OBJECT (demux,
2235 "Didn't find index table segment for position %" G_GINT64_FORMAT,
2240 /* Were we asked for a keyframe ? */
2242 if (segment->edit_unit_byte_count && !segment->n_index_entries) {
2243 GST_LOG_OBJECT (demux,
2244 "Index table without entries, directly using requested position for keyframe search");
2247 GST_LOG_OBJECT (demux, "keyframe search");
2248 /* Search backwards for keyframe */
2249 for (candidate = position; candidate >= segment->index_start_position;
2251 MXFIndexEntry *segment_index_entry =
2252 &segment->index_entries[candidate - segment->index_start_position];
2255 if (segment_index_entry->flags & 0x80) {
2256 GST_LOG_OBJECT (demux, "Found keyframe at position %" G_GINT64_FORMAT,
2258 position = candidate;
2262 /* If a keyframe offset is specified and valid, use that */
2263 if (segment_index_entry->key_frame_offset
2264 && !(segment_index_entry->flags & 0x08)) {
2265 GST_DEBUG_OBJECT (demux, "Using keyframe offset %d",
2266 segment_index_entry->key_frame_offset);
2267 position = candidate + segment_index_entry->key_frame_offset;
2268 if (position < segment->index_start_position) {
2269 GST_DEBUG_OBJECT (demux, "keyframe info is in previous segment");
2270 goto search_in_segment;
2275 /* If we reached the beginning, use that */
2276 if (candidate == 0) {
2277 GST_LOG_OBJECT (demux,
2278 "Reached position 0 while searching for keyframe");
2283 /* If we looped past the beginning of this segment, go to the previous one */
2284 if (candidate == segment->index_start_position) {
2285 position = candidate - 1;
2286 GST_LOG_OBJECT (demux, "Looping with new position %" G_GINT64_FORMAT,
2288 goto search_in_segment;
2291 /* loop back to check previous entry */
2296 /* Figure out the stream offset (also called "body offset" in specification) */
2297 if (segment->edit_unit_byte_count && !segment->n_index_entries) {
2298 /* Constant entry table. */
2299 stream_offset = position * segment->edit_unit_byte_count;
2300 if (etrack->delta_id >= 0) {
2301 MXFDeltaEntry *delta_entry = &segment->delta_entries[etrack->delta_id];
2302 GST_LOG_OBJECT (demux,
2303 "Using delta %d pos_table_index:%d slice:%u element_delta:%u",
2304 etrack->delta_id, delta_entry->pos_table_index, delta_entry->slice,
2305 delta_entry->element_delta);
2306 stream_offset += delta_entry->element_delta;
2307 } else if (etrack->min_edit_units != 1) {
2308 GST_LOG_OBJECT (demux, "Handling minimum edit unit %u",
2309 etrack->min_edit_units);
2311 MIN (etrack->min_edit_units,
2312 (segment->index_start_position + segment->index_duration) - position);
2313 entry->size = segment->edit_unit_byte_count * entry->duration;
2315 entry->size = segment->edit_unit_byte_count;
2317 } else if (segment->n_index_entries) {
2318 MXFIndexEntry *segment_index_entry;
2319 MXFDeltaEntry *delta_entry = NULL;
2320 g_assert (position <=
2321 segment->index_start_position + segment->n_index_entries);
2322 segment_index_entry =
2323 &segment->index_entries[position - segment->index_start_position];
2324 stream_offset = segment_index_entry->stream_offset;
2326 if (segment->n_delta_entries > 0)
2327 delta_entry = &segment->delta_entries[etrack->delta_id];
2330 GST_LOG_OBJECT (demux,
2331 "Using delta %d pos_table_index:%d slice:%u element_delta:%u",
2332 etrack->delta_id, delta_entry->pos_table_index, delta_entry->slice,
2333 delta_entry->element_delta);
2335 /* Apply offset from slice/delta if needed */
2336 if (delta_entry->slice)
2338 segment_index_entry->slice_offset[delta_entry->slice - 1];
2339 stream_offset += delta_entry->element_delta;
2340 if (delta_entry->pos_table_index == -1) {
2341 entry->keyframe = (segment_index_entry->flags & 0x80) == 0x80;
2343 /* FIXME : Handle fractional offset position (delta_entry->pos_table_offset > 0) */
2346 /* Apply reverse temporal reordering if present */
2347 if (index_table->reordered_delta_entry == etrack->delta_id) {
2348 if (position >= index_table->reverse_temporal_offsets->len) {
2349 GST_WARNING_OBJECT (demux,
2350 "Can't apply temporal offset for position %" G_GINT64_FORMAT
2351 " (max:%d)", position, index_table->reverse_temporal_offsets->len);
2353 if (demux->temporal_order_misuse) {
2354 GST_DEBUG_OBJECT (demux, "Handling temporal order misuse");
2355 entry->pts = position + segment_index_entry->temporal_offset;
2358 position + g_array_index (index_table->reverse_temporal_offsets,
2360 GST_LOG_OBJECT (demux,
2361 "Applied temporal offset. dts:%" G_GINT64_FORMAT " pts:%"
2362 G_GINT64_FORMAT, position, entry->pts);
2365 entry->pts = position;
2367 /* Note : This should have been handled in the parser */
2368 GST_WARNING_OBJECT (demux,
2369 "Can't handle index tables without entries nor constant edit unit byte count");
2373 /* Find the partition containing the stream offset for this track */
2375 get_partition_for_stream_offset (demux, etrack, stream_offset);
2377 if (!offset_partition) {
2378 GST_WARNING_OBJECT (demux,
2379 "Couldn't find matching partition for stream offset %" G_GUINT64_FORMAT,
2383 GST_DEBUG_OBJECT (demux, "Entry is in partition %" G_GUINT64_FORMAT,
2384 offset_partition->partition.this_partition);
2387 /* Convert stream offset to absolute offset using matching partition */
2389 offset_partition->partition.this_partition +
2390 offset_partition->essence_container_offset + (stream_offset -
2391 offset_partition->partition.body_offset);
2393 GST_LOG_OBJECT (demux,
2394 "track %d position:%" G_GINT64_FORMAT " stream_offset %" G_GUINT64_FORMAT
2395 " matches to absolute offset %" G_GUINT64_FORMAT, etrack->track_id,
2396 position, stream_offset, absolute_offset);
2397 entry->initialized = TRUE;
2398 entry->offset = absolute_offset;
2399 entry->dts = position;
2405 * find_entry_for_offset:
2406 * @demux: The demuxer
2407 * @etrack: The target essence track
2408 * @offset: An absolute byte offset (excluding run_in)
2409 * @entry: (out): Will be filled with the matching entry information
2411 * Find the entry located at the given absolute byte offset.
2413 * Note: the offset requested should be in the current partition !
2415 * Returns: TRUE if the entry was found and @entry was properly filled, else
2419 find_entry_for_offset (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack,
2420 guint64 offset, GstMXFDemuxIndex * retentry)
2422 GstMXFDemuxIndexTable *index_table = get_track_index_table (demux, etrack);
2424 MXFIndexTableSegment *index_segment = NULL;
2425 GstMXFDemuxPartition *partition = demux->current_partition;
2426 guint64 original_offset = offset;
2427 guint64 cp_offset = 0; /* Offset in Content Package */
2428 MXFIndexEntry *index_entry = NULL;
2429 MXFDeltaEntry *delta_entry = NULL;
2430 gint64 position = 0;
2432 GST_DEBUG_OBJECT (demux,
2433 "track %d body_sid:%d index_sid:%d offset:%" G_GUINT64_FORMAT,
2434 etrack->track_id, etrack->body_sid, etrack->index_sid, offset);
2437 retentry->duration = 1;
2438 retentry->keyframe = TRUE;
2440 /* Index-less search */
2441 if (etrack->offsets) {
2442 for (i = 0; i < etrack->offsets->len; i++) {
2443 GstMXFDemuxIndex *idx =
2444 &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
2446 if (idx->initialized && idx->offset != 0 && idx->offset == offset) {
2448 GST_DEBUG_OBJECT (demux,
2449 "Found in track index. Position:%" G_GINT64_FORMAT, idx->dts);
2455 /* Actual index search */
2456 if (!index_table || !index_table->segments->len) {
2457 GST_WARNING_OBJECT (demux, "No index table or entries to search in");
2462 GST_WARNING_OBJECT (demux, "No current partition for search");
2466 /* Searching for a stream position from an absolute offset works in 3 steps:
2468 * 1. Convert the absolute offset to a "stream offset" based on the partition
2470 * 2. Find the segment for that "stream offset"
2471 * 3. Match the entry within that segment
2474 /* Convert to stream offset */
2475 GST_LOG_OBJECT (demux,
2476 "offset %" G_GUINT64_FORMAT " this_partition:%" G_GUINT64_FORMAT
2477 " essence_container_offset:%" G_GINT64_FORMAT " partition body offset %"
2478 G_GINT64_FORMAT, offset, partition->partition.this_partition,
2479 partition->essence_container_offset, partition->partition.body_offset);
2481 offset - partition->partition.this_partition -
2482 partition->essence_container_offset + partition->partition.body_offset;
2484 GST_LOG_OBJECT (demux, "stream offset %" G_GUINT64_FORMAT, offset);
2486 /* Find the segment that covers the given stream offset (the highest one that
2487 * covers that offset) */
2488 for (i = index_table->segments->len - 1; i >= 0; i--) {
2490 &g_array_index (index_table->segments, MXFIndexTableSegment, i);
2491 GST_DEBUG_OBJECT (demux,
2492 "Checking segment #%d (essence_offset %" G_GUINT64_FORMAT ")", i,
2493 index_segment->segment_start_offset);
2494 /* Not in the right segment yet */
2495 if (offset >= index_segment->segment_start_offset) {
2496 GST_LOG_OBJECT (demux, "Found");
2500 if (!index_segment) {
2501 GST_WARNING_OBJECT (demux,
2502 "Couldn't find index table segment for given offset");
2506 /* In the right segment, figure out:
2507 * * the offset in the content package,
2508 * * the position in edit units
2509 * * the matching entry (if the table has entries)
2511 if (index_segment->edit_unit_byte_count) {
2512 cp_offset = offset % index_segment->edit_unit_byte_count;
2513 position = offset / index_segment->edit_unit_byte_count;
2514 /* Boundary check */
2515 if ((position < index_segment->index_start_position)
2516 || (index_segment->index_duration
2518 (index_segment->index_start_position +
2519 index_segment->index_duration))) {
2520 GST_WARNING_OBJECT (demux,
2521 "Invalid offset, exceeds table segment limits");
2524 if (etrack->min_edit_units != 1) {
2525 retentry->duration = MIN (etrack->min_edit_units,
2526 (index_segment->index_start_position +
2527 index_segment->index_duration) - position);
2528 retentry->size = index_segment->edit_unit_byte_count * retentry->duration;
2530 retentry->size = index_segment->edit_unit_byte_count;
2533 /* Find the content package entry containing this offset */
2535 for (cpidx = 0; cpidx < index_segment->n_index_entries; cpidx++) {
2536 index_entry = &index_segment->index_entries[cpidx];
2537 GST_DEBUG_OBJECT (demux,
2538 "entry #%u offset:%" G_GUINT64_FORMAT " stream_offset:%"
2539 G_GUINT64_FORMAT, cpidx, offset, index_entry->stream_offset);
2540 if (index_entry->stream_offset == offset) {
2541 index_entry = &index_segment->index_entries[cpidx];
2542 /* exactly on the entry */
2543 cp_offset = offset - index_entry->stream_offset;
2544 position = index_segment->index_start_position + cpidx;
2547 if (index_entry->stream_offset > offset && cpidx > 0) {
2548 index_entry = &index_segment->index_entries[cpidx - 1];
2549 /* One too far, result is in previous entry */
2550 cp_offset = offset - index_entry->stream_offset;
2551 position = index_segment->index_start_position + cpidx - 1;
2555 if (cpidx == index_segment->n_index_entries) {
2556 GST_WARNING_OBJECT (demux,
2557 "offset exceeds maximum number of entries in table segment");
2562 /* If the track comes from an interleaved essence container and doesn't have a
2563 * delta_id set, figure it out now */
2564 if (G_UNLIKELY (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN)) {
2566 GST_DEBUG_OBJECT (demux,
2567 "Unknown delta_id for track. Attempting to resolve it");
2569 if (index_segment->n_delta_entries == 0) {
2570 /* No delta entries, nothing we can do about this */
2571 GST_DEBUG_OBJECT (demux, "Index table has no delta entries, ignoring");
2572 etrack->delta_id = MXF_INDEX_DELTA_ID_IGNORE;
2573 } else if (!index_entry) {
2574 for (delta = 0; delta < index_segment->n_delta_entries; delta++) {
2575 /* No entry, therefore no slices */
2576 GST_LOG_OBJECT (demux,
2577 "delta #%d offset %" G_GUINT64_FORMAT " cp_offs:%" G_GUINT64_FORMAT
2578 " element_delta:%u", delta, offset, cp_offset,
2579 index_segment->delta_entries[delta].element_delta);
2580 if (cp_offset == index_segment->delta_entries[delta].element_delta) {
2581 GST_DEBUG_OBJECT (demux, "Matched to delta %d", delta);
2582 etrack->delta_id = delta;
2583 delta_entry = &index_segment->delta_entries[delta];
2588 for (delta = 0; delta < index_segment->n_delta_entries; delta++) {
2589 guint64 delta_offs = 0;
2590 /* If we are not in the first slice, take that offset into account */
2591 if (index_segment->delta_entries[delta].slice)
2593 index_entry->slice_offset[index_segment->
2594 delta_entries[delta].slice - 1];
2595 /* Add the offset for this delta */
2596 delta_offs += index_segment->delta_entries[delta].element_delta;
2597 if (cp_offset == delta_offs) {
2598 GST_DEBUG_OBJECT (demux, "Matched to delta %d", delta);
2599 etrack->delta_id = delta;
2600 delta_entry = &index_segment->delta_entries[delta];
2606 /* If we didn't managed to match, ignore it from now on */
2607 if (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN) {
2608 GST_WARNING_OBJECT (demux,
2609 "Couldn't match delta id, ignoring it from now on");
2610 etrack->delta_id = MXF_INDEX_DELTA_ID_IGNORE;
2612 } else if (index_segment->n_delta_entries > 0) {
2613 delta_entry = &index_segment->delta_entries[etrack->delta_id];
2616 if (index_entry && delta_entry && delta_entry->pos_table_index == -1) {
2617 retentry->keyframe = (index_entry->flags & 0x80) == 0x80;
2618 if (!demux->temporal_order_misuse)
2620 position + g_array_index (index_table->reverse_temporal_offsets,
2623 retentry->pts = position + index_entry->temporal_offset;
2624 GST_LOG_OBJECT (demux,
2625 "Applied temporal offset. dts:%" G_GINT64_FORMAT " pts:%"
2626 G_GINT64_FORMAT, position, retentry->pts);
2628 retentry->pts = position;
2630 /* FIXME : check if position and cp_offs matches the table */
2631 GST_LOG_OBJECT (demux, "Found in index table. position:%" G_GINT64_FORMAT,
2633 retentry->initialized = TRUE;
2634 retentry->offset = original_offset;
2635 retentry->dts = position;
2640 static GstFlowReturn
2641 gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
2642 GstMXFKLV * klv, gboolean peek)
2644 GstFlowReturn ret = GST_FLOW_OK;
2645 guint32 track_number;
2647 GstBuffer *inbuf = NULL;
2648 GstBuffer *outbuf = NULL;
2649 GstMXFDemuxEssenceTrack *etrack = NULL;
2650 /* As in GstMXFDemuxIndex */
2651 guint64 pts = G_MAXUINT64;
2652 gint32 max_temporal_offset = 0;
2653 GstMXFDemuxIndex index_entry = { 0, };
2656 GST_DEBUG_OBJECT (demux,
2657 "Handling generic container essence element of size %" G_GSIZE_FORMAT
2658 " at offset %" G_GUINT64_FORMAT, klv->length,
2659 klv->offset + klv->consumed);
2661 GST_DEBUG_OBJECT (demux, " type = 0x%02x", klv->key.u[12]);
2662 GST_DEBUG_OBJECT (demux, " essence element count = 0x%02x", klv->key.u[13]);
2663 GST_DEBUG_OBJECT (demux, " essence element type = 0x%02x", klv->key.u[14]);
2664 GST_DEBUG_OBJECT (demux, " essence element number = 0x%02x", klv->key.u[15]);
2666 if (demux->current_partition->essence_container_offset == 0) {
2667 demux->current_partition->essence_container_offset =
2668 demux->offset - demux->current_partition->partition.this_partition -
2670 if (demux->current_partition->single_track
2671 && demux->current_partition->single_track->wrapping !=
2672 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2673 demux->current_partition->essence_container_offset += klv->data_offset;
2674 demux->current_partition->clip_klv = *klv;
2675 /* "consume" the initial bytes of the KLV */
2676 klv->consumed = klv->data_offset;
2677 GST_DEBUG_OBJECT (demux,
2678 "Non-frame wrapping, updated essence_container_offset to %"
2679 G_GUINT64_FORMAT, demux->current_partition->essence_container_offset);
2683 if (!demux->current_package) {
2684 GST_ERROR_OBJECT (demux, "No package selected yet");
2685 return GST_FLOW_ERROR;
2688 if (demux->src->len == 0) {
2689 GST_ERROR_OBJECT (demux, "No streams created yet");
2690 return GST_FLOW_ERROR;
2693 if (demux->essence_tracks->len == 0) {
2694 GST_ERROR_OBJECT (demux, "No essence streams found in the metadata");
2695 return GST_FLOW_ERROR;
2698 /* Identify and fetch the essence track */
2699 track_number = GST_READ_UINT32_BE (&klv->key.u[12]);
2701 etrack = demux->current_partition->single_track;
2703 for (i = 0; i < demux->essence_tracks->len; i++) {
2704 GstMXFDemuxEssenceTrack *tmp =
2705 g_ptr_array_index (demux->essence_tracks, i);
2707 if (tmp->body_sid == demux->current_partition->partition.body_sid &&
2708 (tmp->track_number == track_number || tmp->track_number == 0)) {
2715 GST_DEBUG_OBJECT (demux,
2716 "No essence track for this essence element found");
2721 GST_DEBUG_OBJECT (demux,
2722 "Handling generic container essence (track %d , position:%"
2723 G_GINT64_FORMAT ", number: 0x%08x , frame-wrapped:%d)", etrack->track_id,
2724 etrack->position, track_number,
2725 etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
2727 /* Fetch the current entry.
2729 * 1. If we don't have a current position, use find_entry_for_offset()
2730 * 2. If we do have a position, use find_edit_entry()
2732 * 3. If we are dealing with frame-wrapped content, pull the corresponding
2733 * data from upstream (because it wasn't provided). If we didn't find an
2734 * entry, error out because we can't deal with a frame-wrapped stream
2738 offset = klv->offset + klv->consumed;
2740 /* Update the track position (in case of resyncs) */
2741 if (etrack->position == -1) {
2742 GST_DEBUG_OBJECT (demux,
2743 "Unknown essence track position, looking into index");
2744 if (!find_entry_for_offset (demux, etrack, offset - demux->run_in,
2746 GST_WARNING_OBJECT (demux, "Essence track position not in index");
2749 /* Update track position */
2750 etrack->position = index_entry.dts;
2751 } else if (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN) {
2752 GST_DEBUG_OBJECT (demux,
2753 "Unknown essence track delta_id, looking into index");
2754 if (!find_entry_for_offset (demux, etrack, offset - demux->run_in,
2756 /* Non-fatal, fallback to legacy mode */
2757 GST_WARNING_OBJECT (demux, "Essence track position not in index");
2758 } else if (etrack->position != index_entry.dts) {
2759 GST_ERROR_OBJECT (demux,
2760 "track position doesn't match %" G_GINT64_FORMAT " entry dts %"
2761 G_GINT64_FORMAT, etrack->position, index_entry.dts);
2762 return GST_FLOW_ERROR;
2765 if (!find_edit_entry (demux, etrack, etrack->position, FALSE, &index_entry)) {
2766 GST_DEBUG_OBJECT (demux, "Couldn't find entry");
2767 } else if (etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2768 if (etrack->delta_id != MXF_INDEX_DELTA_ID_IGNORE
2769 && index_entry.offset != offset) {
2770 GST_ERROR_OBJECT (demux,
2771 "demux offset doesn't match %" G_GINT64_FORMAT " entry offset %"
2772 G_GUINT64_FORMAT, offset, index_entry.offset);
2773 return GST_FLOW_ERROR;
2775 } else if (index_entry.offset != klv->offset + klv->consumed &&
2776 index_entry.offset != klv->offset + klv->data_offset) {
2777 GST_ERROR_OBJECT (demux,
2778 "KLV offset doesn't match %" G_GINT64_FORMAT " entry offset %"
2779 G_GUINT64_FORMAT, klv->offset + klv->consumed, index_entry.offset);
2780 return GST_FLOW_ERROR;
2784 if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2785 /* We need entry information to deal with non-frame-wrapped content */
2786 if (!index_entry.initialized) {
2787 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2788 ("Essence with non-frame-wrapping require an index table to be present"));
2789 return GST_FLOW_ERROR;
2791 /* We cannot deal with non-frame-wrapping in push mode for now */
2792 if (!demux->random_access) {
2793 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2794 ("Non-frame-wrapping is not support in push mode"));
2795 return GST_FLOW_ERROR;
2799 /* FIXME : If we're peeking and don't need to actually parse the data, we
2800 * should avoid pulling the content from upstream */
2801 if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2802 g_assert (index_entry.size);
2803 GST_DEBUG_OBJECT (demux, "Should only grab %" G_GUINT64_FORMAT " bytes",
2806 gst_mxf_demux_pull_range (demux, index_entry.offset, index_entry.size,
2808 if (ret != GST_FLOW_OK)
2810 if (klv->consumed == 0)
2811 klv->consumed = klv->data_offset + index_entry.size;
2813 klv->consumed += index_entry.size;
2814 if (klv != &demux->current_partition->clip_klv)
2815 demux->current_partition->clip_klv = *klv;
2816 GST_LOG_OBJECT (demux,
2817 "klv data_offset:%" G_GUINT64_FORMAT " length:%" G_GSIZE_FORMAT
2818 " consumed:%" G_GUINT64_FORMAT, klv->data_offset, klv->length,
2820 /* Switch back to KLV mode if we're done with this one */
2821 if (klv->length + klv->data_offset == klv->consumed)
2822 demux->state = GST_MXF_DEMUX_STATE_KLV;
2824 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
2827 ret = gst_mxf_demux_fill_klv (demux, klv);
2828 if (ret != GST_FLOW_OK)
2831 /* Create subbuffer to be able to change metadata */
2833 gst_buffer_copy_region (klv->data, GST_BUFFER_COPY_ALL, 0,
2834 gst_buffer_get_size (klv->data));
2838 if (index_entry.initialized) {
2839 GST_DEBUG_OBJECT (demux, "Got entry dts:%" G_GINT64_FORMAT " keyframe:%d",
2840 index_entry.dts, index_entry.keyframe);
2842 if (index_entry.initialized && !index_entry.keyframe)
2843 GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT);
2845 if (etrack->handle_func) {
2846 /* Takes ownership of inbuf */
2848 etrack->handle_func (&klv->key, inbuf, etrack->caps,
2849 etrack->source_track, etrack->mapping_data, &outbuf);
2857 if (ret != GST_FLOW_OK) {
2858 GST_ERROR_OBJECT (demux, "Failed to handle essence element");
2860 gst_buffer_unref (outbuf);
2866 if (!index_entry.initialized) {
2867 /* This can happen when doing scanning without entry tables */
2868 index_entry.duration = 1;
2869 index_entry.offset = demux->offset - demux->run_in;
2870 index_entry.dts = etrack->position;
2871 index_entry.pts = etrack->intra_only ? etrack->position : G_MAXUINT64;
2872 index_entry.keyframe =
2873 !GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
2874 index_entry.initialized = TRUE;
2875 GST_DEBUG_OBJECT (demux,
2876 "Storing newly discovered information on track %d. dts: %"
2877 G_GINT64_FORMAT " offset:%" G_GUINT64_FORMAT " keyframe:%d",
2878 etrack->track_id, index_entry.dts, index_entry.offset,
2879 index_entry.keyframe);
2881 if (!etrack->offsets)
2882 etrack->offsets = g_array_new (FALSE, TRUE, sizeof (GstMXFDemuxIndex));
2884 /* We only ever append to the track offset entry. */
2885 g_assert (etrack->position <= etrack->offsets->len);
2886 g_array_insert_val (etrack->offsets, etrack->position, index_entry);
2893 GST_DEBUG_OBJECT (demux, "No output buffer created");
2900 max_temporal_offset = get_track_max_temporal_offset (demux, etrack);
2902 for (i = 0; i < demux->src->len; i++) {
2903 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
2905 if (pad->current_essence_track != etrack)
2909 GST_DEBUG_OBJECT (pad, "Pad is already EOS");
2913 if (etrack->position < pad->current_essence_track_position) {
2914 GST_DEBUG_OBJECT (pad,
2915 "Not at current component's position (track:%" G_GINT64_FORMAT
2916 " essence:%" G_GINT64_FORMAT ")", etrack->position,
2917 pad->current_essence_track_position);
2922 GstMXFDemuxPad *earliest = gst_mxf_demux_get_earliest_pad (demux);
2924 if (earliest && earliest != pad && earliest->position < pad->position &&
2925 pad->position - earliest->position > demux->max_drift) {
2926 GST_DEBUG_OBJECT (earliest,
2927 "Pad is too far ahead of time (%" GST_TIME_FORMAT " vs earliest:%"
2928 GST_TIME_FORMAT ")", GST_TIME_ARGS (earliest->position),
2929 GST_TIME_ARGS (pad->position));
2934 /* Create another subbuffer to have writable metadata */
2936 gst_buffer_copy_region (inbuf, GST_BUFFER_COPY_ALL, 0,
2937 gst_buffer_get_size (inbuf));
2939 pts = index_entry.pts;
2941 GST_BUFFER_DTS (outbuf) = pad->position;
2942 if (etrack->intra_only) {
2943 GST_BUFFER_PTS (outbuf) = pad->position;
2944 } else if (pts != G_MAXUINT64) {
2945 GST_BUFFER_PTS (outbuf) = gst_util_uint64_scale (pts * GST_SECOND,
2946 pad->current_essence_track->source_track->edit_rate.d,
2947 pad->current_essence_track->source_track->edit_rate.n);
2948 GST_BUFFER_PTS (outbuf) +=
2949 gst_util_uint64_scale (pad->current_component_start_position *
2950 GST_SECOND, pad->material_track->edit_rate.d,
2951 pad->material_track->edit_rate.n);
2952 /* We are dealing with reordered data, the PTS is shifted forward by the
2953 * maximum temporal reordering (the DTS remain as-is). */
2954 if (max_temporal_offset > 0)
2955 GST_BUFFER_PTS (outbuf) +=
2956 gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
2957 pad->current_essence_track->source_track->edit_rate.d,
2958 pad->current_essence_track->source_track->edit_rate.n);
2961 GST_BUFFER_PTS (outbuf) = GST_CLOCK_TIME_NONE;
2964 GST_BUFFER_DURATION (outbuf) =
2965 gst_util_uint64_scale (GST_SECOND,
2966 index_entry.duration *
2967 pad->current_essence_track->source_track->edit_rate.d,
2968 pad->current_essence_track->source_track->edit_rate.n);
2969 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
2970 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
2972 if (pad->material_track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE
2973 && pad->start_timecode.config.fps_n != 0
2974 && pad->start_timecode.config.fps_d != 0) {
2975 if (etrack->intra_only) {
2976 GstVideoTimeCode timecode = pad->start_timecode;
2978 gst_video_time_code_add_frames (&timecode,
2979 pad->current_material_track_position);
2980 gst_buffer_add_video_time_code_meta (outbuf, &timecode);
2981 } else if (pts != G_MAXUINT64) {
2982 GstVideoTimeCode timecode = pad->start_timecode;
2984 gst_video_time_code_add_frames (&timecode,
2985 pad->current_component_start_position);
2986 gst_video_time_code_add_frames (&timecode,
2987 gst_util_uint64_scale (pts,
2988 pad->material_track->edit_rate.n *
2989 pad->current_essence_track->source_track->edit_rate.d,
2990 pad->material_track->edit_rate.d *
2991 pad->current_essence_track->source_track->edit_rate.n));
2992 gst_buffer_add_video_time_code_meta (outbuf, &timecode);
2997 /* Update accumulated error and compensate */
3000 (GST_SECOND * pad->current_essence_track->source_track->edit_rate.d) %
3001 pad->current_essence_track->source_track->edit_rate.n;
3002 pad->position_accumulated_error +=
3003 ((gdouble) abs_error) /
3004 ((gdouble) pad->current_essence_track->source_track->edit_rate.n);
3006 if (pad->position_accumulated_error >= 1.0) {
3007 GST_BUFFER_DURATION (outbuf) += 1;
3008 pad->position_accumulated_error -= 1.0;
3011 if (pad->need_segment) {
3014 if (demux->close_seg_event)
3015 gst_pad_push_event (GST_PAD_CAST (pad),
3016 gst_event_ref (demux->close_seg_event));
3018 if (max_temporal_offset > 0) {
3019 GstSegment shift_segment;
3020 /* Handle maximum temporal offset. We are shifting all output PTS for
3021 * this stream by the greatest temporal reordering that can occur. In
3022 * order not to change the stream/running time we shift the segment
3023 * start and stop values accordingly */
3024 gst_segment_copy_into (&demux->segment, &shift_segment);
3025 if (GST_CLOCK_TIME_IS_VALID (shift_segment.start))
3026 shift_segment.start +=
3027 gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
3028 pad->current_essence_track->source_track->edit_rate.d,
3029 pad->current_essence_track->source_track->edit_rate.n);
3030 if (GST_CLOCK_TIME_IS_VALID (shift_segment.stop))
3031 shift_segment.stop +=
3032 gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
3033 pad->current_essence_track->source_track->edit_rate.d,
3034 pad->current_essence_track->source_track->edit_rate.n);
3035 e = gst_event_new_segment (&shift_segment);
3037 e = gst_event_new_segment (&demux->segment);
3038 GST_DEBUG_OBJECT (pad, "Sending segment %" GST_PTR_FORMAT, e);
3039 gst_event_set_seqnum (e, demux->seqnum);
3040 gst_pad_push_event (GST_PAD_CAST (pad), e);
3041 pad->need_segment = FALSE;
3045 gst_pad_push_event (GST_PAD_CAST (pad), gst_event_new_tag (pad->tags));
3049 pad->position += GST_BUFFER_DURATION (outbuf);
3050 pad->current_material_track_position += index_entry.duration;
3053 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
3054 pad->discont = FALSE;
3057 /* Handlers can provide empty GAP buffers to indicate that the parsed
3058 * content was valid but that nothing meaningful needs to be outputted. In
3059 * such cases we send out a GAP event instead */
3060 if (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP) &&
3061 gst_buffer_get_size (outbuf) == 0) {
3062 GstEvent *gap = gst_event_new_gap (GST_BUFFER_DTS (outbuf),
3063 GST_BUFFER_DURATION (outbuf));
3064 gst_buffer_unref (outbuf);
3065 GST_DEBUG_OBJECT (pad,
3066 "Replacing empty gap buffer with gap event %" GST_PTR_FORMAT, gap);
3067 gst_pad_push_event (GST_PAD_CAST (pad), gap);
3069 GST_DEBUG_OBJECT (pad,
3070 "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u: pts %"
3071 GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT
3072 " position %" G_GUINT64_FORMAT, gst_buffer_get_size (outbuf),
3073 pad->material_track->parent.track_id,
3074 GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
3075 GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
3076 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
3077 pad->current_essence_track_position);
3079 ret = gst_pad_push (GST_PAD_CAST (pad), outbuf);
3082 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
3083 GST_LOG_OBJECT (pad, "combined return %s", gst_flow_get_name (ret));
3085 if (pad->position > demux->segment.position)
3086 demux->segment.position = pad->position;
3088 if (ret != GST_FLOW_OK)
3091 pad->current_essence_track_position += index_entry.duration;
3093 if (pad->current_component) {
3094 if (pad->current_component_duration > 0 &&
3095 pad->current_essence_track_position - pad->current_component_start
3096 >= pad->current_component_duration) {
3097 GST_DEBUG_OBJECT (demux, "Switching to next component");
3100 gst_mxf_demux_pad_set_component (demux, pad,
3101 pad->current_component_index + 1);
3102 if (ret == GST_FLOW_OK) {
3103 pad->current_essence_track->position =
3104 pad->current_essence_track_position;
3105 } else if (ret != GST_FLOW_EOS) {
3106 GST_ERROR_OBJECT (demux, "Switching component failed");
3108 } else if (etrack->duration > 0
3109 && pad->current_essence_track_position >= etrack->duration) {
3110 GST_DEBUG_OBJECT (demux,
3111 "Current component position after end of essence track");
3114 } else if (etrack->duration > 0
3115 && pad->current_essence_track_position == etrack->duration) {
3116 GST_DEBUG_OBJECT (demux, "At the end of the essence track");
3120 if (ret == GST_FLOW_EOS) {
3123 GST_DEBUG_OBJECT (pad, "EOS for track");
3125 e = gst_event_new_eos ();
3126 gst_event_set_seqnum (e, demux->seqnum);
3127 gst_pad_push_event (GST_PAD_CAST (pad), e);
3131 if (ret != GST_FLOW_OK)
3137 gst_buffer_unref (inbuf);
3140 gst_buffer_unref (outbuf);
3142 etrack->position += index_entry.duration;
3148 * Called when analyzing the (RIP) Random Index Pack.
3150 * FIXME : If a file doesn't have a RIP, we should iterate the partition headers
3151 * to collect as much information as possible.
3153 * This function collects as much information as possible from the partition headers:
3154 * * Store partition information in the list of partitions
3155 * * Handle any index table segment present
3158 read_partition_header (GstMXFDemux * demux)
3162 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv) != GST_FLOW_OK
3163 || !mxf_is_partition_pack (&klv.key)) {
3167 if (gst_mxf_demux_handle_partition_pack (demux, &klv) != GST_FLOW_OK) {
3169 gst_buffer_unref (klv.data);
3172 gst_mxf_demux_consume_klv (demux, &klv);
3174 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv) != GST_FLOW_OK)
3177 while (mxf_is_fill (&klv.key)) {
3178 gst_mxf_demux_consume_klv (demux, &klv);
3179 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3180 &klv) != GST_FLOW_OK)
3184 if (!mxf_is_index_table_segment (&klv.key)
3185 && demux->current_partition->partition.header_byte_count) {
3186 demux->offset += demux->current_partition->partition.header_byte_count;
3187 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3188 &klv) != GST_FLOW_OK)
3192 while (mxf_is_fill (&klv.key)) {
3193 gst_mxf_demux_consume_klv (demux, &klv);
3194 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3195 &klv) != GST_FLOW_OK)
3199 if (demux->current_partition->partition.index_byte_count
3200 && mxf_is_index_table_segment (&klv.key)) {
3201 guint64 index_end_offset =
3202 demux->offset + demux->current_partition->partition.index_byte_count;
3204 while (demux->offset < index_end_offset) {
3205 if (mxf_is_index_table_segment (&klv.key))
3206 gst_mxf_demux_handle_index_table_segment (demux, &klv);
3207 gst_mxf_demux_consume_klv (demux, &klv);
3209 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3210 &klv) != GST_FLOW_OK)
3215 while (mxf_is_fill (&klv.key)) {
3216 gst_mxf_demux_consume_klv (demux, &klv);
3217 if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3218 &klv) != GST_FLOW_OK)
3222 if (mxf_is_generic_container_system_item (&klv.key) ||
3223 mxf_is_generic_container_essence_element (&klv.key) ||
3224 mxf_is_avid_essence_container_essence_element (&klv.key)) {
3225 if (demux->current_partition->essence_container_offset == 0)
3226 demux->current_partition->essence_container_offset =
3227 demux->offset - demux->current_partition->partition.this_partition -
3232 static GstFlowReturn
3233 gst_mxf_demux_handle_random_index_pack (GstMXFDemux * demux, GstMXFKLV * klv)
3239 GstFlowReturn flowret;
3241 GST_DEBUG_OBJECT (demux,
3242 "Handling random index pack of size %" G_GSIZE_FORMAT " at offset %"
3243 G_GUINT64_FORMAT, klv->length, klv->offset);
3245 if (demux->random_index_pack) {
3246 GST_DEBUG_OBJECT (demux, "Already parsed random index pack");
3250 flowret = gst_mxf_demux_fill_klv (demux, klv);
3251 if (flowret != GST_FLOW_OK)
3254 gst_buffer_map (klv->data, &map, GST_MAP_READ);
3256 mxf_random_index_pack_parse (&klv->key, map.data, map.size,
3257 &demux->random_index_pack);
3258 gst_buffer_unmap (klv->data, &map);
3261 GST_ERROR_OBJECT (demux, "Parsing random index pack failed");
3262 return GST_FLOW_ERROR;
3265 for (i = 0; i < demux->random_index_pack->len; i++) {
3266 GstMXFDemuxPartition *p = NULL;
3267 MXFRandomIndexPackEntry *e =
3268 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry, i);
3270 if (e->offset < demux->run_in) {
3271 GST_ERROR_OBJECT (demux, "Invalid random index pack entry");
3272 return GST_FLOW_ERROR;
3275 for (l = demux->partitions; l; l = l->next) {
3276 GstMXFDemuxPartition *tmp = l->data;
3278 if (tmp->partition.this_partition + demux->run_in == e->offset) {
3285 p = g_new0 (GstMXFDemuxPartition, 1);
3286 p->partition.this_partition = e->offset - demux->run_in;
3287 p->partition.body_sid = e->body_sid;
3289 g_list_insert_sorted (demux->partitions, p,
3290 (GCompareFunc) gst_mxf_demux_partition_compare);
3294 for (l = demux->partitions; l; l = l->next) {
3295 GstMXFDemuxPartition *a, *b;
3297 if (l->next == NULL)
3303 b->partition.prev_partition = a->partition.this_partition;
3310 compare_index_table_segment (MXFIndexTableSegment * sa,
3311 MXFIndexTableSegment * sb)
3313 if (sa->body_sid != sb->body_sid)
3314 return (sa->body_sid < sb->body_sid) ? -1 : 1;
3315 if (sa->index_sid != sb->index_sid)
3316 return (sa->index_sid < sb->index_sid) ? -1 : 1;
3317 if (sa->index_start_position != sb->index_start_position)
3318 return (sa->index_start_position < sb->index_start_position) ? -1 : 1;
3320 /* If all the above are equal ... the index table segments are only equal if
3321 * their instance ID are equal. Until March 2022 the FFmpeg MXF muxer would
3322 * write the same instance id for the various (different) index table
3323 * segments, we therefore only check instance ID *after* all the above
3324 * properties to make sure they are really different. */
3325 if (mxf_uuid_is_equal (&sa->instance_id, &sb->instance_id))
3331 static GstFlowReturn
3332 gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux, GstMXFKLV * klv)
3334 MXFIndexTableSegment *segment;
3338 GstFlowReturn flowret;
3340 flowret = gst_mxf_demux_fill_klv (demux, klv);
3341 if (flowret != GST_FLOW_OK)
3344 GST_DEBUG_OBJECT (demux,
3345 "Handling index table segment of size %" G_GSIZE_FORMAT " at offset %"
3346 G_GUINT64_FORMAT, klv->length, klv->offset);
3348 segment = g_new0 (MXFIndexTableSegment, 1);
3350 gst_buffer_map (klv->data, &map, GST_MAP_READ);
3351 ret = mxf_index_table_segment_parse (&klv->key, segment, map.data, map.size);
3352 gst_buffer_unmap (klv->data, &map);
3355 GST_ERROR_OBJECT (demux, "Parsing index table segment failed");
3357 return GST_FLOW_ERROR;
3360 /* Drop it if we already saw it. Ideally we should be able to do this before
3361 parsing (by checking instance UID) */
3362 if (g_list_find_custom (demux->pending_index_table_segments, segment,
3363 (GCompareFunc) compare_index_table_segment)) {
3364 GST_DEBUG_OBJECT (demux, "Already in pending list");
3365 mxf_index_table_segment_reset (segment);
3369 for (tmp = demux->index_tables; tmp; tmp = tmp->next) {
3370 GstMXFDemuxIndexTable *table = (GstMXFDemuxIndexTable *) tmp->data;
3371 if (g_array_binary_search (table->segments, segment,
3372 (GCompareFunc) compare_index_table_segment, NULL)) {
3373 GST_DEBUG_OBJECT (demux, "Already handled");
3374 mxf_index_table_segment_reset (segment);
3380 demux->pending_index_table_segments =
3381 g_list_insert_sorted (demux->pending_index_table_segments, segment,
3382 (GCompareFunc) compare_index_table_segment);
3387 static GstFlowReturn
3388 gst_mxf_demux_peek_klv_packet (GstMXFDemux * demux, guint64 offset,
3391 GstBuffer *buffer = NULL;
3393 GstFlowReturn ret = GST_FLOW_OK;
3395 #ifndef GST_DISABLE_GST_DEBUG
3399 memset (klv, 0, sizeof (GstMXFKLV));
3400 klv->offset = offset;
3402 /* Pull 16 byte key and first byte of BER encoded length */
3404 gst_mxf_demux_pull_range (demux, offset, 17, &buffer)) != GST_FLOW_OK)
3407 gst_buffer_map (buffer, &map, GST_MAP_READ);
3409 memcpy (&klv->key, map.data, 16);
3411 /* Decode BER encoded packet length */
3412 if ((map.data[16] & 0x80) == 0) {
3413 klv->length = map.data[16];
3414 klv->data_offset = 17;
3416 guint slen = map.data[16] & 0x7f;
3418 klv->data_offset = 16 + 1 + slen;
3420 gst_buffer_unmap (buffer, &map);
3421 gst_buffer_unref (buffer);
3424 /* Must be at most 8 according to SMPTE-379M 5.3.4 */
3426 GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
3427 ret = GST_FLOW_ERROR;
3431 /* Now pull the length of the packet */
3432 if ((ret = gst_mxf_demux_pull_range (demux, offset + 17, slen,
3433 &buffer)) != GST_FLOW_OK)
3436 gst_buffer_map (buffer, &map, GST_MAP_READ);
3441 klv->length = (klv->length << 8) | *data;
3447 gst_buffer_unmap (buffer, &map);
3448 gst_buffer_unref (buffer);
3451 /* GStreamer's buffer sizes are stored in a guint so we
3452 * limit ourself to G_MAXUINT large buffers */
3453 if (klv->length > G_MAXUINT) {
3454 GST_ERROR_OBJECT (demux,
3455 "Unsupported KLV packet length: %" G_GSIZE_FORMAT, klv->length);
3456 ret = GST_FLOW_ERROR;
3460 GST_DEBUG_OBJECT (demux,
3461 "Found KLV packet at offset %" G_GUINT64_FORMAT " with key %s and length "
3462 "%" G_GSIZE_FORMAT, offset, mxf_ul_to_string (&klv->key, str),
3467 gst_buffer_unref (buffer);
3472 static GstFlowReturn
3473 gst_mxf_demux_fill_klv (GstMXFDemux * demux, GstMXFKLV * klv)
3477 GST_DEBUG_OBJECT (demux,
3478 "Pulling %" G_GSIZE_FORMAT " bytes from offset %" G_GUINT64_FORMAT,
3479 klv->length, klv->offset + klv->data_offset);
3480 return gst_mxf_demux_pull_range (demux, klv->offset + klv->data_offset,
3481 klv->length, &klv->data);
3484 /* Call when done with a klv. Will release the buffer (if any) and will update
3485 * the demuxer offset position. Do *NOT* call if you do not want the demuxer
3486 * offset to be updated */
3488 gst_mxf_demux_consume_klv (GstMXFDemux * demux, GstMXFKLV * klv)
3491 gst_buffer_unref (klv->data);
3494 GST_DEBUG_OBJECT (demux,
3495 "Consuming KLV offset:%" G_GUINT64_FORMAT " data_offset:%"
3496 G_GUINT64_FORMAT " length:%" G_GSIZE_FORMAT " consumed:%"
3497 G_GUINT64_FORMAT, klv->offset, klv->data_offset, klv->length,
3500 demux->offset = klv->offset + klv->consumed;
3502 demux->offset += klv->data_offset + klv->length;
3506 gst_mxf_demux_pull_random_index_pack (GstMXFDemux * demux)
3509 gint64 filesize = -1;
3510 GstFormat fmt = GST_FORMAT_BYTES;
3512 guint64 old_offset = demux->offset;
3514 GstFlowReturn flow_ret;
3517 if (!gst_pad_peer_query_duration (demux->sinkpad, fmt, &filesize) ||
3518 fmt != GST_FORMAT_BYTES || filesize == -1) {
3519 GST_DEBUG_OBJECT (demux, "Can't query upstream size");
3523 g_assert (filesize > 4);
3526 if (gst_mxf_demux_pull_range (demux, filesize - 4, 4, &buffer) != GST_FLOW_OK) {
3527 GST_DEBUG_OBJECT (demux, "Failed pulling last 4 bytes");
3531 gst_buffer_map (buffer, &map, GST_MAP_READ);
3532 pack_size = GST_READ_UINT32_BE (map.data);
3533 gst_buffer_unmap (buffer, &map);
3535 gst_buffer_unref (buffer);
3537 if (pack_size < 20) {
3538 GST_DEBUG_OBJECT (demux, "Too small pack size (%u bytes)", pack_size);
3540 } else if (pack_size > filesize - 20) {
3541 GST_DEBUG_OBJECT (demux, "Too large pack size (%u bytes)", pack_size);
3545 /* Peek for klv at filesize - pack_size */
3546 if (gst_mxf_demux_peek_klv_packet (demux, filesize - pack_size,
3547 &klv) != GST_FLOW_OK) {
3548 GST_DEBUG_OBJECT (demux, "Failed pulling random index pack key");
3552 if (!mxf_is_random_index_pack (&klv.key)) {
3553 GST_DEBUG_OBJECT (demux, "No random index pack");
3557 demux->offset = filesize - pack_size;
3558 flow_ret = gst_mxf_demux_handle_random_index_pack (demux, &klv);
3560 gst_buffer_unref (klv.data);
3561 demux->offset = old_offset;
3563 if (flow_ret == GST_FLOW_OK && !demux->index_table_segments_collected) {
3564 collect_index_table_segments (demux);
3565 demux->index_table_segments_collected = TRUE;
3570 gst_mxf_demux_parse_footer_metadata (GstMXFDemux * demux)
3572 guint64 old_offset = demux->offset;
3574 GstFlowReturn flow = GST_FLOW_OK;
3575 GstMXFDemuxPartition *old_partition = demux->current_partition;
3577 GST_DEBUG_OBJECT (demux, "Parsing footer metadata");
3579 demux->current_partition = NULL;
3581 gst_mxf_demux_reset_metadata (demux);
3583 if (demux->footer_partition_pack_offset != 0) {
3584 demux->offset = demux->run_in + demux->footer_partition_pack_offset;
3586 MXFRandomIndexPackEntry *entry =
3587 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry,
3588 demux->random_index_pack->len - 1);
3589 demux->offset = entry->offset;
3593 GST_LOG_OBJECT (demux, "Peeking partition pack at offset %" G_GUINT64_FORMAT,
3596 /* Process Partition Pack */
3597 flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3598 if (G_UNLIKELY (flow != GST_FLOW_OK))
3601 if (!mxf_is_partition_pack (&klv.key))
3604 if (gst_mxf_demux_handle_partition_pack (demux, &klv) != GST_FLOW_OK) {
3606 gst_buffer_unref (klv.data);
3610 gst_mxf_demux_consume_klv (demux, &klv);
3612 /* If there's no Header Metadata in this partition, jump to the previous
3614 if (demux->current_partition->partition.header_byte_count == 0) {
3615 /* Reached the first partition, bail out */
3616 if (demux->current_partition->partition.this_partition == 0)
3620 demux->run_in + demux->current_partition->partition.prev_partition;
3624 /* Next up should be an optional fill pack followed by a primer pack */
3626 flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3627 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3628 /* If ever we can't get the next KLV, jump to the previous partition */
3629 if (!demux->current_partition->partition.prev_partition)
3632 demux->run_in + demux->current_partition->partition.prev_partition;
3636 if (mxf_is_fill (&klv.key)) {
3637 gst_mxf_demux_consume_klv (demux, &klv);
3638 } else if (mxf_is_primer_pack (&klv.key)) {
3639 /* Update primer mapping if present (jump to previous if it failed) */
3640 if (!demux->current_partition->primer.mappings) {
3641 if (gst_mxf_demux_handle_primer_pack (demux, &klv) != GST_FLOW_OK) {
3642 gst_mxf_demux_consume_klv (demux, &klv);
3643 if (!demux->current_partition->partition.prev_partition)
3647 demux->current_partition->partition.prev_partition;
3651 gst_mxf_demux_consume_klv (demux, &klv);
3654 if (!demux->current_partition->partition.prev_partition)
3657 demux->run_in + demux->current_partition->partition.prev_partition;
3662 /* parse metadata for this partition */
3663 while (demux->offset <
3664 demux->run_in + demux->current_partition->primer.offset +
3665 demux->current_partition->partition.header_byte_count) {
3666 flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3667 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3668 if (!demux->current_partition->partition.prev_partition)
3671 demux->run_in + demux->current_partition->partition.prev_partition;
3675 if (mxf_is_metadata (&klv.key)) {
3676 flow = gst_mxf_demux_handle_metadata (demux, &klv);
3677 gst_mxf_demux_consume_klv (demux, &klv);
3679 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3680 gst_mxf_demux_reset_metadata (demux);
3681 if (!demux->current_partition->partition.prev_partition)
3684 demux->run_in + demux->current_partition->partition.prev_partition;
3687 } else if (mxf_is_descriptive_metadata (&klv.key)) {
3688 gst_mxf_demux_handle_descriptive_metadata (demux, &klv);
3689 gst_mxf_demux_consume_klv (demux, &klv);
3691 gst_mxf_demux_consume_klv (demux, &klv);
3695 /* resolve references etc */
3696 if (!demux->preface || gst_mxf_demux_resolve_references (demux) !=
3697 GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
3698 /* Don't attempt to parse metadata from this partition again */
3699 demux->current_partition->parsed_metadata = TRUE;
3700 /* Skip to previous partition or bail out */
3701 if (!demux->current_partition->partition.prev_partition)
3704 demux->run_in + demux->current_partition->partition.prev_partition;
3709 demux->offset = old_offset;
3710 demux->current_partition = old_partition;
3713 static GstFlowReturn
3714 gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, GstMXFKLV * klv,
3717 MXFUL *key = &klv->key;
3718 #ifndef GST_DISABLE_GST_DEBUG
3721 GstFlowReturn ret = GST_FLOW_OK;
3723 if (demux->update_metadata
3725 && (demux->offset >=
3726 demux->run_in + demux->current_partition->primer.offset +
3727 demux->current_partition->partition.header_byte_count ||
3728 mxf_is_generic_container_system_item (key) ||
3729 mxf_is_generic_container_essence_element (key) ||
3730 mxf_is_avid_essence_container_essence_element (key))) {
3731 demux->current_partition->parsed_metadata = TRUE;
3732 if ((ret = gst_mxf_demux_resolve_references (demux)) != GST_FLOW_OK ||
3733 (ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
3736 } else if (demux->metadata_resolved && demux->requested_package_string) {
3737 if ((ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
3742 if (!mxf_is_mxf_packet (key)) {
3743 GST_WARNING_OBJECT (demux,
3744 "Skipping non-MXF packet of size %" G_GSIZE_FORMAT " at offset %"
3745 G_GUINT64_FORMAT ", key: %s", klv->length,
3746 demux->offset, mxf_ul_to_string (key, key_str));
3747 } else if (mxf_is_partition_pack (key)) {
3748 ret = gst_mxf_demux_handle_partition_pack (demux, klv);
3749 } else if (mxf_is_primer_pack (key)) {
3750 ret = gst_mxf_demux_handle_primer_pack (demux, klv);
3751 } else if (mxf_is_metadata (key)) {
3752 ret = gst_mxf_demux_handle_metadata (demux, klv);
3753 } else if (mxf_is_descriptive_metadata (key)) {
3754 ret = gst_mxf_demux_handle_descriptive_metadata (demux, klv);
3755 } else if (mxf_is_generic_container_system_item (key)) {
3756 if (demux->pending_index_table_segments)
3757 collect_index_table_segments (demux);
3758 ret = gst_mxf_demux_handle_generic_container_system_item (demux, klv);
3759 } else if (mxf_is_generic_container_essence_element (key) ||
3760 mxf_is_avid_essence_container_essence_element (key)) {
3761 if (demux->pending_index_table_segments)
3762 collect_index_table_segments (demux);
3764 gst_mxf_demux_handle_generic_container_essence_element (demux, klv,
3766 } else if (mxf_is_random_index_pack (key)) {
3767 ret = gst_mxf_demux_handle_random_index_pack (demux, klv);
3769 if (ret == GST_FLOW_OK && demux->random_access
3770 && !demux->index_table_segments_collected) {
3771 collect_index_table_segments (demux);
3772 demux->index_table_segments_collected = TRUE;
3774 } else if (mxf_is_index_table_segment (key)) {
3775 ret = gst_mxf_demux_handle_index_table_segment (demux, klv);
3776 } else if (mxf_is_fill (key)) {
3777 GST_DEBUG_OBJECT (demux,
3778 "Skipping filler packet of size %" G_GSIZE_FORMAT " at offset %"
3779 G_GUINT64_FORMAT, klv->length, demux->offset);
3781 GST_DEBUG_OBJECT (demux,
3782 "Skipping unknown packet of size %" G_GSIZE_FORMAT " at offset %"
3783 G_GUINT64_FORMAT ", key: %s", klv->length,
3784 demux->offset, mxf_ul_to_string (key, key_str));
3792 gst_mxf_demux_set_partition_for_offset (GstMXFDemux * demux, guint64 offset)
3796 GST_LOG_OBJECT (demux, "offset %" G_GUINT64_FORMAT, offset);
3798 /* This partition will already be parsed, otherwise
3799 * the position wouldn't be in the index */
3800 for (l = demux->partitions; l; l = l->next) {
3801 GstMXFDemuxPartition *p = l->data;
3803 if (p->partition.this_partition + demux->run_in <= offset)
3804 demux->current_partition = p;
3806 if (demux->current_partition)
3807 GST_DEBUG_OBJECT (demux,
3808 "Current partition now %p (body_sid:%d index_sid:%d this_partition:%"
3809 G_GUINT64_FORMAT ")", demux->current_partition,
3810 demux->current_partition->partition.body_sid,
3811 demux->current_partition->partition.index_sid,
3812 demux->current_partition->partition.this_partition);
3814 GST_DEBUG_OBJECT (demux, "Haven't found partition for offset yet");
3818 find_closest_offset (GArray * offsets, gint64 * position, gboolean keyframe)
3820 GstMXFDemuxIndex *idx;
3821 gint64 current_position = *position;
3823 if (!offsets || offsets->len == 0)
3826 current_position = MIN (current_position, offsets->len - 1);
3828 idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
3829 while (idx->offset == 0 || (keyframe && !idx->keyframe)) {
3831 if (current_position < 0)
3833 idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
3836 if (idx->offset != 0 && (!keyframe || idx->keyframe)) {
3837 *position = current_position;
3845 gst_mxf_demux_find_essence_element (GstMXFDemux * demux,
3846 GstMXFDemuxEssenceTrack * etrack, gint64 * position, gboolean keyframe)
3848 GstFlowReturn ret = GST_FLOW_OK;
3849 guint64 old_offset = demux->offset;
3850 GstMXFDemuxPartition *old_partition = demux->current_partition;
3853 gint64 requested_position = *position, index_start_position;
3854 GstMXFDemuxIndex index_entry = { 0, };
3856 GST_DEBUG_OBJECT (demux, "Trying to find essence element %" G_GINT64_FORMAT
3857 " of track 0x%08x with body_sid %u (keyframe %d)", *position,
3858 etrack->track_number, etrack->body_sid, keyframe);
3860 /* Get entry from index table if present */
3861 if (find_edit_entry (demux, etrack, *position, keyframe, &index_entry)) {
3862 GST_DEBUG_OBJECT (demux,
3863 "Got position %" G_GINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
3864 index_entry.dts, index_entry.offset);
3865 *position = index_entry.dts;
3866 return index_entry.offset;
3869 GST_DEBUG_OBJECT (demux, "Not found in index table");
3871 /* Fallback to track offsets */
3873 if (!demux->random_access) {
3874 /* Best effort for push mode */
3875 offset = find_closest_offset (etrack->offsets, position, keyframe);
3877 GST_DEBUG_OBJECT (demux,
3878 "Starting with edit unit %" G_GINT64_FORMAT " for %" G_GINT64_FORMAT
3879 " in generated index at offset %" G_GUINT64_FORMAT, *position,
3880 requested_position, offset);
3884 if (etrack->duration > 0 && *position >= etrack->duration) {
3885 GST_WARNING_OBJECT (demux, "Position after end of essence track");
3891 index_start_position = *position;
3893 demux->offset = demux->run_in;
3895 offset = find_closest_offset (etrack->offsets, &index_start_position, FALSE);
3897 demux->offset = offset + demux->run_in;
3898 GST_DEBUG_OBJECT (demux,
3899 "Starting with edit unit %" G_GINT64_FORMAT " for %" G_GINT64_FORMAT
3900 " in generated index at offset %" G_GUINT64_FORMAT,
3901 index_start_position, requested_position, offset);
3903 index_start_position = -1;
3906 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
3908 for (i = 0; i < demux->essence_tracks->len; i++) {
3909 GstMXFDemuxEssenceTrack *t = g_ptr_array_index (demux->essence_tracks, i);
3911 if (index_start_position != -1 && t == etrack)
3912 t->position = index_start_position;
3914 t->position = (demux->offset == demux->run_in) ? 0 : -1;
3915 GST_LOG_OBJECT (demux, "Setting track %d position to %" G_GINT64_FORMAT,
3916 t->track_id, t->position);
3919 /* Else peek at all essence elements and complete our
3920 * index until we find the requested element
3922 while (ret == GST_FLOW_OK) {
3925 GST_LOG_OBJECT (demux, "Pulling from offset %" G_GINT64_FORMAT,
3927 ret = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3929 if (ret == GST_FLOW_EOS) {
3931 for (i = 0; i < demux->essence_tracks->len; i++) {
3932 GstMXFDemuxEssenceTrack *t =
3933 g_ptr_array_index (demux->essence_tracks, i);
3935 if (t->position > 0)
3936 t->duration = t->position;
3938 /* For the searched track this is really our position */
3939 etrack->duration = etrack->position;
3941 for (i = 0; i < demux->src->len; i++) {
3942 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3945 && p->current_essence_track_position >=
3946 p->current_essence_track->duration) {
3950 e = gst_event_new_eos ();
3951 gst_event_set_seqnum (e, demux->seqnum);
3952 gst_pad_push_event (GST_PAD_CAST (p), e);
3957 GST_LOG_OBJECT (demux,
3958 "pulling gave flow:%s track->position:%" G_GINT64_FORMAT,
3959 gst_flow_get_name (ret), etrack->position);
3960 if (G_UNLIKELY (ret != GST_FLOW_OK) && etrack->position <= *position) {
3961 demux->offset = old_offset;
3962 demux->current_partition = old_partition;
3964 } else if (G_UNLIKELY (ret == GST_FLOW_OK)) {
3965 ret = gst_mxf_demux_handle_klv_packet (demux, &klv, TRUE);
3966 gst_mxf_demux_consume_klv (demux, &klv);
3969 GST_LOG_OBJECT (demux,
3970 "Handling gave flow:%s track->position:%" G_GINT64_FORMAT
3971 " looking for %" G_GINT64_FORMAT, gst_flow_get_name (ret),
3972 etrack->position, *position);
3974 /* If we found the position read it from the index again */
3975 if (((ret == GST_FLOW_OK && etrack->position == *position + 1) ||
3976 (ret == GST_FLOW_EOS && etrack->position == *position + 1))
3977 && etrack->offsets && etrack->offsets->len > *position
3978 && g_array_index (etrack->offsets, GstMXFDemuxIndex,
3979 *position).offset != 0) {
3980 GST_DEBUG_OBJECT (demux, "Found at offset %" G_GUINT64_FORMAT,
3982 demux->offset = old_offset;
3983 demux->current_partition = old_partition;
3984 if (find_edit_entry (demux, etrack, *position, keyframe, &index_entry)) {
3985 GST_DEBUG_OBJECT (demux,
3986 "Got position %" G_GINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
3987 index_entry.dts, index_entry.offset);
3988 *position = index_entry.dts;
3989 return index_entry.offset;
3991 goto from_track_offset;
3994 demux->offset = old_offset;
3995 demux->current_partition = old_partition;
3997 GST_DEBUG_OBJECT (demux, "Not found in this file");
4002 static GstFlowReturn
4003 gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
4006 GstFlowReturn ret = GST_FLOW_OK;
4007 gboolean force_switch = FALSE;
4009 if (demux->src->len > 0) {
4010 if (!gst_mxf_demux_get_earliest_pad (demux)) {
4012 GST_DEBUG_OBJECT (demux, "All tracks are EOS");
4017 if (demux->state == GST_MXF_DEMUX_STATE_ESSENCE) {
4018 g_assert (demux->current_partition->single_track
4019 && demux->current_partition->single_track->wrapping !=
4020 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
4021 /* Feeding essence directly (i.e. in the middle of a custom/clip KLV) */
4023 gst_mxf_demux_handle_generic_container_essence_element (demux,
4024 &demux->current_partition->clip_klv, FALSE);
4025 gst_mxf_demux_consume_klv (demux, &demux->current_partition->clip_klv);
4026 if (ret == GST_FLOW_OK
4027 && demux->current_partition->single_track->position >=
4028 demux->current_partition->single_track->duration) {
4029 /* We are done with the contents of this clip/custom wrapping, force the
4030 * switch to the next non-EOS track */
4031 GST_DEBUG_OBJECT (demux, "Single track EOS, switch");
4032 force_switch = TRUE;
4037 ret = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
4041 * Move this EOS handling to a separate function
4043 if (ret == GST_FLOW_EOS && demux->src->len > 0) {
4045 GstMXFDemuxPad *p = NULL;
4047 GST_DEBUG_OBJECT (demux, "EOS HANDLING");
4049 for (i = 0; i < demux->src->len; i++) {
4050 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4052 GST_DEBUG_OBJECT (p,
4053 "eos:%d current_essence_track_position:%" G_GINT64_FORMAT
4054 " position:%" G_GINT64_FORMAT " duration:%" G_GINT64_FORMAT, p->eos,
4055 p->current_essence_track_position,
4056 p->current_essence_track->position,
4057 p->current_essence_track->duration);
4059 && p->current_essence_track->position >=
4060 p->current_essence_track->duration) {
4064 e = gst_event_new_eos ();
4065 gst_event_set_seqnum (e, demux->seqnum);
4066 gst_pad_push_event (GST_PAD_CAST (p), e);
4070 while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
4074 GST_DEBUG_OBJECT (p, "Trying on earliest");
4076 position = p->current_essence_track_position;
4079 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
4084 GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
4086 e = gst_event_new_eos ();
4087 gst_event_set_seqnum (e, demux->seqnum);
4088 gst_pad_push_event (GST_PAD_CAST (p), e);
4092 demux->offset = offset + demux->run_in;
4093 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4094 if (p->current_essence_track->wrapping !=
4095 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4096 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4097 demux->current_partition->clip_klv.consumed =
4098 offset - demux->current_partition->clip_klv.offset;
4100 demux->state = GST_MXF_DEMUX_STATE_KLV;
4101 p->current_essence_track->position = position;
4107 if (G_UNLIKELY (ret != GST_FLOW_OK))
4110 ret = gst_mxf_demux_handle_klv_packet (demux, &klv, FALSE);
4111 gst_mxf_demux_consume_klv (demux, &klv);
4113 /* We entered a new partition */
4114 if (ret == GST_FLOW_OK && mxf_is_partition_pack (&klv.key)) {
4115 GstMXFDemuxPartition *partition = demux->current_partition;
4116 gboolean partition_done = FALSE;
4118 /* Grab footer metadata if needed */
4119 if (demux->pull_footer_metadata
4120 && partition->partition.type == MXF_PARTITION_PACK_HEADER
4121 && (!partition->partition.closed || !partition->partition.complete)
4122 && (demux->footer_partition_pack_offset != 0
4123 || demux->random_index_pack)) {
4124 GST_DEBUG_OBJECT (demux,
4125 "Open or incomplete header partition, trying to get final metadata from the last partitions");
4126 gst_mxf_demux_parse_footer_metadata (demux);
4127 demux->pull_footer_metadata = FALSE;
4130 /* If the partition has some content, do post-checks */
4131 if (partition->partition.body_sid != 0) {
4132 guint64 lowest_offset = G_MAXUINT64;
4133 GST_DEBUG_OBJECT (demux,
4134 "Entered partition (body_sid:%d index_sid:%d body_offset:%"
4135 G_GUINT64_FORMAT "), checking positions",
4136 partition->partition.body_sid, partition->partition.index_sid,
4137 partition->partition.body_offset);
4139 if (partition->single_track) {
4140 /* Fast-path for single track partition */
4141 if (partition->single_track->position == -1
4142 && partition->partition.body_offset == 0) {
4143 GST_DEBUG_OBJECT (demux,
4144 "First time in partition, setting track position to 0");
4145 partition->single_track->position = 0;
4146 } else if (partition->single_track->position == -1) {
4147 GST_ERROR_OBJECT (demux,
4148 "Unknown track position, consuming data from first partition entry");
4150 partition->partition.this_partition +
4151 partition->essence_container_offset;
4152 partition->clip_klv.consumed = 0;
4153 } else if (partition->single_track->position != 0) {
4154 GstMXFDemuxIndex entry;
4155 GST_DEBUG_OBJECT (demux,
4156 "Track already at another position : %" G_GINT64_FORMAT,
4157 partition->single_track->position);
4158 if (find_edit_entry (demux, partition->single_track,
4159 partition->single_track->position, FALSE, &entry)) {
4160 lowest_offset = entry.offset;
4161 } else if (partition->single_track->position >=
4162 partition->single_track->duration) {
4163 GST_DEBUG_OBJECT (demux, "Track fully consumed, partition done");
4164 partition_done = TRUE;
4169 for (i = 0; i < demux->essence_tracks->len; i++) {
4170 GstMXFDemuxEssenceTrack *etrack =
4171 g_ptr_array_index (demux->essence_tracks, i);
4173 if (etrack->body_sid != partition->partition.body_sid)
4175 if (etrack->position == -1 && partition->partition.body_offset == 0) {
4176 GST_DEBUG_OBJECT (demux, "Resetting track %d to position 0",
4179 etrack->position = 0;
4180 } else if (etrack->position != 0) {
4181 GstMXFDemuxIndex entry;
4182 if (find_edit_entry (demux, etrack,
4183 etrack->position, FALSE, &entry)) {
4184 if (lowest_offset == G_MAXUINT64
4185 || entry.offset < lowest_offset)
4186 lowest_offset = entry.offset;
4192 if (partition_done || lowest_offset != G_MAXUINT64) {
4193 GstMXFDemuxPartition *next_partition = NULL;
4194 GList *cur_part = g_list_find (demux->partitions, partition);
4195 if (cur_part && cur_part->next)
4196 next_partition = (GstMXFDemuxPartition *) cur_part->next->data;
4198 /* If we have completely processed this partition, skip to next partition */
4200 || lowest_offset > next_partition->partition.this_partition) {
4201 GST_DEBUG_OBJECT (demux,
4202 "Partition entirely processed, skipping to next one");
4203 demux->offset = next_partition->partition.this_partition;
4205 GST_DEBUG_OBJECT (demux,
4206 "Skipping to demuxer offset %" G_GUINT64_FORMAT " (from %"
4207 G_GUINT64_FORMAT ")", lowest_offset, demux->offset);
4208 demux->offset = lowest_offset;
4209 if (partition->single_track
4210 && partition->single_track->wrapping !=
4211 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4212 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4213 demux->current_partition->clip_klv.consumed =
4214 demux->offset - demux->current_partition->clip_klv.offset;
4222 if (ret == GST_FLOW_OK && demux->src->len > 0
4223 && demux->essence_tracks->len > 0) {
4224 GstMXFDemuxPad *earliest = NULL;
4225 /* We allow time drifts of at most 500ms */
4226 while ((earliest = gst_mxf_demux_get_earliest_pad (demux)) && (force_switch
4227 || demux->segment.position - earliest->position >
4228 demux->max_drift)) {
4232 GST_DEBUG_OBJECT (demux,
4233 "Found synchronization issue -- trying to solve");
4235 position = earliest->current_essence_track_position;
4237 /* FIXME: This can probably be improved by using the
4238 * offset of position-1 if it's in the same partition
4239 * or the start of the position otherwise.
4240 * This way we won't skip elements from the same essence
4241 * container as etrack->position
4244 gst_mxf_demux_find_essence_element (demux,
4245 earliest->current_essence_track, &position, FALSE);
4249 GST_WARNING_OBJECT (demux,
4250 "Failed to find offset for late essence track");
4251 earliest->eos = TRUE;
4252 e = gst_event_new_eos ();
4253 gst_event_set_seqnum (e, demux->seqnum);
4254 gst_pad_push_event (GST_PAD_CAST (earliest), e);
4258 demux->offset = offset + demux->run_in;
4259 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4260 GST_DEBUG_OBJECT (demux,
4261 "Switching to offset %" G_GUINT64_FORMAT " for position %"
4262 G_GINT64_FORMAT " on track %d (body_sid:%d index_sid:%d)",
4263 demux->offset, position, earliest->current_essence_track->track_id,
4264 earliest->current_essence_track->body_sid,
4265 earliest->current_essence_track->index_sid);
4266 if (demux->current_partition->single_track
4267 && demux->current_partition->single_track->wrapping !=
4268 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4269 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4270 demux->current_partition->clip_klv.consumed =
4271 offset - demux->current_partition->clip_klv.offset;
4273 demux->state = GST_MXF_DEMUX_STATE_KLV;
4275 earliest->current_essence_track->position = position;
4276 GST_DEBUG_OBJECT (earliest, "Switching to this pad");
4286 gst_mxf_demux_loop (GstPad * pad)
4288 GstMXFDemux *demux = NULL;
4289 GstFlowReturn flow = GST_FLOW_OK;
4291 demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
4293 if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4296 /* Skip run-in, which is at most 64K and is finished
4297 * by a header partition pack */
4298 while (demux->offset < 64 * 1024) {
4300 gst_mxf_demux_peek_klv_packet (demux, demux->offset,
4301 &klv)) != GST_FLOW_OK)
4304 if (mxf_is_header_partition_pack (&klv.key)) {
4305 GST_DEBUG_OBJECT (demux,
4306 "Found header partition pack at offset %" G_GUINT64_FORMAT,
4308 demux->state = GST_MXF_DEMUX_STATE_KLV;
4309 demux->run_in = demux->offset;
4315 if (G_UNLIKELY (demux->run_in == -1)) {
4316 GST_ERROR_OBJECT (demux, "No valid header partition pack found");
4317 flow = GST_FLOW_ERROR;
4321 /* Grab the RIP at the end of the file (if present) */
4322 gst_mxf_demux_pull_random_index_pack (demux);
4325 /* Now actually do something */
4326 flow = gst_mxf_demux_pull_and_handle_klv_packet (demux);
4328 /* pause if something went wrong */
4329 if (G_UNLIKELY (flow != GST_FLOW_OK))
4332 /* check EOS condition */
4333 if ((demux->segment.stop != -1) &&
4334 (demux->segment.position >= demux->segment.stop)) {
4336 gboolean eos = TRUE;
4338 for (i = 0; i < demux->src->len; i++) {
4339 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4341 if (!p->eos && p->position < demux->segment.stop) {
4348 flow = GST_FLOW_EOS;
4353 gst_object_unref (demux);
4359 const gchar *reason = gst_flow_get_name (flow);
4361 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
4362 gst_pad_pause_task (pad);
4364 if (flow == GST_FLOW_EOS) {
4365 /* perform EOS logic */
4366 if (demux->src->len == 0) {
4367 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
4368 ("This stream contains no data."),
4369 ("got eos and didn't find any streams"));
4370 } else if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4375 /* for segment playback we need to post when (in stream time)
4376 * we stopped, this is either stop (when set) or the duration. */
4377 if ((stop = demux->segment.stop) == -1)
4378 stop = demux->segment.duration;
4380 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
4381 m = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
4382 GST_FORMAT_TIME, stop);
4383 gst_message_set_seqnum (m, demux->seqnum);
4384 gst_element_post_message (GST_ELEMENT_CAST (demux), m);
4385 e = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
4386 gst_event_set_seqnum (e, demux->seqnum);
4387 gst_mxf_demux_push_src_event (demux, e);
4391 /* normal playback, send EOS to all linked pads */
4392 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
4393 e = gst_event_new_eos ();
4394 gst_event_set_seqnum (e, demux->seqnum);
4395 if (!gst_mxf_demux_push_src_event (demux, e)) {
4396 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
4399 } else if (flow == GST_FLOW_NOT_LINKED || flow < GST_FLOW_EOS) {
4402 GST_ELEMENT_FLOW_ERROR (demux, flow);
4403 e = gst_event_new_eos ();
4404 gst_event_set_seqnum (e, demux->seqnum);
4405 gst_mxf_demux_push_src_event (demux, e);
4407 gst_object_unref (demux);
4412 static GstFlowReturn
4413 gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
4415 GstFlowReturn ret = GST_FLOW_OK;
4416 GstMXFDemux *demux = NULL;
4417 const guint8 *data = NULL;
4420 #ifndef GST_DISABLE_GST_DEBUG
4424 demux = GST_MXF_DEMUX (parent);
4426 GST_LOG_OBJECT (demux,
4427 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
4428 G_GUINT64_FORMAT, gst_buffer_get_size (inbuf), GST_BUFFER_OFFSET (inbuf));
4430 if (demux->src->len > 0) {
4431 if (!gst_mxf_demux_get_earliest_pad (demux)) {
4433 GST_DEBUG_OBJECT (demux, "All tracks are EOS");
4438 if (G_UNLIKELY (GST_BUFFER_OFFSET (inbuf) == 0)) {
4439 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
4442 demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
4445 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (inbuf) != 0)) {
4446 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
4447 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
4448 demux->offset = GST_BUFFER_OFFSET (inbuf);
4449 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4450 } else if (demux->current_partition == NULL) {
4451 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4454 gst_adapter_push (demux->adapter, inbuf);
4457 while (ret == GST_FLOW_OK) {
4458 if (G_UNLIKELY (demux->flushing)) {
4459 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
4460 ret = GST_FLOW_FLUSHING;
4464 if (gst_adapter_available (demux->adapter) < 16)
4467 if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4468 /* Skip run-in, which is at most 64K and is finished
4469 * by a header partition pack */
4471 while (demux->offset < 64 * 1024
4472 && gst_adapter_available (demux->adapter) >= 16) {
4473 data = gst_adapter_map (demux->adapter, 16);
4474 res = mxf_is_header_partition_pack ((const MXFUL *) data);
4475 gst_adapter_unmap (demux->adapter);
4478 GST_DEBUG_OBJECT (demux,
4479 "Found header partition pack at offset %" G_GUINT64_FORMAT,
4481 demux->run_in = demux->offset;
4482 demux->state = GST_MXF_DEMUX_STATE_KLV;
4485 gst_adapter_flush (demux->adapter, 1);
4488 } else if (demux->offset < demux->run_in) {
4489 guint64 flush = MIN (gst_adapter_available (demux->adapter),
4490 demux->run_in - demux->offset);
4491 gst_adapter_flush (demux->adapter, flush);
4492 demux->offset += flush;
4496 if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4497 /* Need more data */
4498 if (demux->offset < 64 * 1024)
4501 GST_ERROR_OBJECT (demux, "No valid header partition pack found");
4502 ret = GST_FLOW_ERROR;
4506 if (gst_adapter_available (demux->adapter) < 17)
4509 /* FIXME : Handle non-klv state */
4510 g_assert (demux->state == GST_MXF_DEMUX_STATE_KLV);
4512 /* Now actually do something */
4513 memset (&klv, 0, sizeof (GstMXFKLV));
4515 /* Pull 16 byte key and first byte of BER encoded length */
4516 data = gst_adapter_map (demux->adapter, 17);
4518 memcpy (&klv.key, data, 16);
4520 GST_DEBUG_OBJECT (demux, "Got KLV packet with key %s",
4521 mxf_ul_to_string (&klv.key, str));
4523 /* Decode BER encoded packet length */
4524 if ((data[16] & 0x80) == 0) {
4525 klv.length = data[16];
4526 klv.data_offset = 17;
4528 guint slen = data[16] & 0x7f;
4530 klv.data_offset = 16 + 1 + slen;
4532 gst_adapter_unmap (demux->adapter);
4534 /* Must be at most 8 according to SMPTE-379M 5.3.4 and
4535 * GStreamer buffers can only have a 4 bytes length */
4537 GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
4538 ret = GST_FLOW_ERROR;
4542 if (gst_adapter_available (demux->adapter) < 17 + slen)
4545 data = gst_adapter_map (demux->adapter, 17 + slen);
4550 klv.length = (klv.length << 8) | *data;
4556 gst_adapter_unmap (demux->adapter);
4558 /* GStreamer's buffer sizes are stored in a guint so we
4559 * limit ourself to G_MAXUINT large buffers */
4560 if (klv.length > G_MAXUINT) {
4561 GST_ERROR_OBJECT (demux,
4562 "Unsupported KLV packet length: %" G_GSIZE_FORMAT, klv.length);
4563 ret = GST_FLOW_ERROR;
4567 GST_DEBUG_OBJECT (demux, "KLV packet with key %s has length "
4568 "%" G_GSIZE_FORMAT, mxf_ul_to_string (&klv.key, str), klv.length);
4570 if (gst_adapter_available (demux->adapter) < klv.data_offset + klv.length)
4573 gst_adapter_flush (demux->adapter, klv.data_offset);
4575 if (klv.length > 0) {
4576 klv.data = gst_adapter_take_buffer (demux->adapter, klv.length);
4578 ret = gst_mxf_demux_handle_klv_packet (demux, &klv, FALSE);
4580 gst_mxf_demux_consume_klv (demux, &klv);
4586 /* Given a stream time for an output pad, figure out:
4587 * * The Essence track for that stream time
4588 * * The position on that track
4591 gst_mxf_demux_pad_to_track_and_position (GstMXFDemux * demux,
4592 GstMXFDemuxPad * pad, GstClockTime streamtime,
4593 GstMXFDemuxEssenceTrack ** etrack, gint64 * position)
4595 gint64 material_position;
4598 MXFMetadataSourceClip *clip = NULL;
4601 /* Convert to material position */
4603 gst_util_uint64_scale (streamtime, pad->material_track->edit_rate.n,
4604 pad->material_track->edit_rate.d * GST_SECOND);
4606 GST_DEBUG_OBJECT (pad,
4607 "streamtime %" GST_TIME_FORMAT " position %" G_GINT64_FORMAT,
4608 GST_TIME_ARGS (streamtime), material_position);
4611 /* Find sequence component covering that position */
4612 for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
4615 MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
4616 structural_components[i]);
4617 GST_LOG_OBJECT (pad,
4618 "clip %d start_position:%" G_GINT64_FORMAT " duration %"
4619 G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
4620 clip->parent.duration);
4621 if (clip->parent.duration <= 0)
4623 if ((sum + clip->parent.duration) > material_position)
4625 sum += clip->parent.duration;
4628 if (i == pad->material_track->parent.sequence->n_structural_components) {
4629 GST_WARNING_OBJECT (pad, "Requested position beyond the last clip");
4630 /* Outside of current components. Setting to the end of the last clip */
4631 material_position = sum;
4632 sum -= clip->parent.duration;
4635 GST_DEBUG_OBJECT (pad, "Looking for essence track for track_id:%d umid:%s",
4636 clip->source_track_id, mxf_umid_to_string (&clip->source_package_id,
4639 /* Get the corresponding essence track for the given source package and stream id */
4640 for (i = 0; i < demux->essence_tracks->len; i++) {
4641 GstMXFDemuxEssenceTrack *track =
4642 g_ptr_array_index (demux->essence_tracks, i);
4643 GST_LOG_OBJECT (pad, "Looking at essence track body_sid:%d index_sid:%d",
4644 track->body_sid, track->index_sid);
4645 if (clip->source_track_id == 0 || (track->track_id == clip->source_track_id
4646 && mxf_umid_is_equal (&clip->source_package_id,
4647 &track->source_package_uid))) {
4648 GST_DEBUG_OBJECT (pad,
4649 "Found matching essence track body_sid:%d index_sid:%d",
4650 track->body_sid, track->index_sid);
4652 *position = material_position - sum;
4660 /* Given a track+position for a given pad, figure out the resulting stream time */
4662 gst_mxf_demux_pad_get_stream_time (GstMXFDemux * demux,
4663 GstMXFDemuxPad * pad, GstMXFDemuxEssenceTrack * etrack,
4664 gint64 position, GstClockTime * stream_time)
4668 MXFMetadataSourceClip *clip = NULL;
4670 /* Find the component for that */
4671 /* Find sequence component covering that position */
4672 for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
4675 MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
4676 structural_components[i]);
4677 GST_LOG_OBJECT (pad,
4678 "clip %d start_position:%" G_GINT64_FORMAT " duration %"
4679 G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
4680 clip->parent.duration);
4681 if (etrack->track_id == clip->source_track_id
4682 && mxf_umid_is_equal (&clip->source_package_id,
4683 &etrack->source_package_uid)) {
4684 /* This is the clip */
4687 /* Fetch in the next one */
4688 sum += clip->parent.duration;
4691 /* Theoretically impossible */
4692 if (i == pad->material_track->parent.sequence->n_structural_components) {
4693 /* Outside of current components ?? */
4698 gst_util_uint64_scale (position + sum,
4699 pad->material_track->edit_rate.d * GST_SECOND,
4700 pad->material_track->edit_rate.n);
4706 gst_mxf_demux_pad_set_position (GstMXFDemux * demux, GstMXFDemuxPad * p,
4711 MXFMetadataSourceClip *clip = NULL;
4713 if (!p->current_component) {
4714 p->current_essence_track_position =
4715 gst_util_uint64_scale (start, p->material_track->edit_rate.n,
4716 p->material_track->edit_rate.d * GST_SECOND);
4718 if (p->current_essence_track_position >= p->current_essence_track->duration
4719 && p->current_essence_track->duration > 0) {
4720 p->current_essence_track_position = p->current_essence_track->duration;
4722 gst_util_uint64_scale (p->current_essence_track->duration,
4723 p->material_track->edit_rate.d * GST_SECOND,
4724 p->material_track->edit_rate.n);
4726 p->position = start;
4728 p->position_accumulated_error = 0.0;
4729 p->current_material_track_position = p->current_essence_track_position;
4734 for (i = 0; i < p->material_track->parent.sequence->n_structural_components;
4737 MXF_METADATA_SOURCE_CLIP (p->material_track->parent.sequence->
4738 structural_components[i]);
4740 if (clip->parent.duration <= 0)
4743 sum += clip->parent.duration;
4745 if (gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4746 p->material_track->edit_rate.n) > start)
4750 if (i == p->material_track->parent.sequence->n_structural_components) {
4752 gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4753 p->material_track->edit_rate.n);
4754 p->position_accumulated_error = 0.0;
4755 p->current_material_track_position = sum;
4757 gst_mxf_demux_pad_set_component (demux, p, i);
4761 if (clip->parent.duration > 0)
4762 sum -= clip->parent.duration;
4765 gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4766 p->material_track->edit_rate.n);
4768 gst_mxf_demux_pad_set_component (demux, p, i);
4771 gint64 essence_offset = gst_util_uint64_scale (start,
4772 p->current_essence_track->source_track->edit_rate.n,
4773 p->current_essence_track->source_track->edit_rate.d * GST_SECOND);
4775 p->current_essence_track_position += essence_offset;
4777 p->position = gst_util_uint64_scale (sum,
4778 GST_SECOND * p->material_track->edit_rate.d,
4779 p->material_track->edit_rate.n) + gst_util_uint64_scale (essence_offset,
4780 GST_SECOND * p->current_essence_track->source_track->edit_rate.d,
4781 p->current_essence_track->source_track->edit_rate.n);
4782 p->position_accumulated_error = 0.0;
4783 p->current_material_track_position = sum + essence_offset;
4786 if (p->current_essence_track_position >= p->current_essence_track->duration
4787 && p->current_essence_track->duration > 0) {
4788 p->current_essence_track_position = p->current_essence_track->duration;
4790 gst_util_uint64_scale (sum + p->current_component->parent.duration,
4791 p->material_track->edit_rate.d * GST_SECOND,
4792 p->material_track->edit_rate.n);
4793 p->position_accumulated_error = 0.0;
4794 p->current_material_track_position =
4795 sum + p->current_component->parent.duration;
4800 gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event)
4804 GstSeekType start_type, stop_type;
4807 gboolean update, flush, keyframe;
4808 GstSegment seeksegment;
4812 gst_event_parse_seek (event, &rate, &format, &flags,
4813 &start_type, &start, &stop_type, &stop);
4814 seqnum = gst_event_get_seqnum (event);
4819 if (format != GST_FORMAT_TIME)
4822 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
4823 keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
4825 /* Work on a copy until we are sure the seek succeeded. */
4826 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
4828 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
4831 /* Apply the seek to our segment */
4832 gst_segment_do_seek (&seeksegment, rate, format, flags,
4833 start_type, start, stop_type, stop, &update);
4835 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
4838 if (flush || seeksegment.position != demux->segment.position) {
4840 guint64 new_offset = -1;
4843 if (!demux->metadata_resolved || demux->update_metadata) {
4844 if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
4845 gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
4846 goto unresolved_metadata;
4850 /* Do the actual seeking */
4851 for (i = 0; i < demux->src->len; i++) {
4852 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4856 /* Reset EOS flag on all pads */
4858 gst_mxf_demux_pad_set_position (demux, p, start);
4860 position = p->current_essence_track_position;
4861 off = gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
4862 &position, keyframe);
4863 new_offset = MIN (off, new_offset);
4867 if (new_offset == -1)
4870 new_offset += demux->run_in;
4872 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
4873 G_GUINT64_FORMAT, new_offset);
4874 e = gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
4875 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
4876 new_offset, GST_SEEK_TYPE_NONE, 0);
4877 gst_event_set_seqnum (e, seqnum);
4878 ret = gst_pad_push_event (demux->sinkpad, e);
4880 if (G_UNLIKELY (!ret)) {
4885 /* Tell all the stream a new segment is needed */
4886 for (i = 0; i < demux->src->len; i++) {
4887 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4888 p->need_segment = TRUE;
4891 for (i = 0; i < demux->essence_tracks->len; i++) {
4892 GstMXFDemuxEssenceTrack *t = g_ptr_array_index (demux->essence_tracks, i);
4896 /* Ok seek succeeded, take the newly configured segment */
4897 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
4904 GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
4905 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4909 GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
4912 unresolved_metadata:
4914 GST_WARNING_OBJECT (demux, "metadata can't be resolved");
4915 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4919 GST_WARNING_OBJECT (demux, "upstream seek failed");
4920 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4924 GST_WARNING_OBJECT (demux, "can't find new offset");
4925 return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4930 collect_index_table_segments (GstMXFDemux * demux)
4934 guint64 old_offset = demux->offset;
4935 GstMXFDemuxPartition *old_partition = demux->current_partition;
4937 /* This function can also be called when a RIP is not present. This can happen
4938 * if index table segments were discovered while scanning the file */
4939 if (demux->random_index_pack) {
4940 for (i = 0; i < demux->random_index_pack->len; i++) {
4941 MXFRandomIndexPackEntry *e =
4942 &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry, i);
4944 if (e->offset < demux->run_in) {
4945 GST_ERROR_OBJECT (demux, "Invalid random index pack entry");
4949 demux->offset = e->offset;
4950 read_partition_header (demux);
4953 demux->offset = old_offset;
4954 demux->current_partition = old_partition;
4957 if (demux->pending_index_table_segments == NULL) {
4958 GST_DEBUG_OBJECT (demux, "No pending index table segments to collect");
4962 GST_LOG_OBJECT (demux, "Collecting pending index table segments");
4964 for (l = demux->pending_index_table_segments; l; l = l->next) {
4965 MXFIndexTableSegment *segment = l->data;
4966 GstMXFDemuxIndexTable *t = NULL;
4969 #ifndef GST_DISABLE_GST_DEBUG
4973 GST_LOG_OBJECT (demux,
4974 "Collecting from segment bodySID:%d indexSID:%d instance_id: %s",
4975 segment->body_sid, segment->index_sid,
4976 mxf_uuid_to_string (&segment->instance_id, str));
4978 for (k = demux->index_tables; k; k = k->next) {
4979 GstMXFDemuxIndexTable *tmp = k->data;
4981 if (tmp->body_sid == segment->body_sid
4982 && tmp->index_sid == segment->index_sid) {
4989 t = g_new0 (GstMXFDemuxIndexTable, 1);
4990 t->body_sid = segment->body_sid;
4991 t->index_sid = segment->index_sid;
4992 t->max_temporal_offset = 0;
4993 t->segments = g_array_new (FALSE, TRUE, sizeof (MXFIndexTableSegment));
4994 g_array_set_clear_func (t->segments,
4995 (GDestroyNotify) mxf_index_table_segment_reset);
4996 t->reordered_delta_entry = -1;
4997 t->reverse_temporal_offsets = g_array_new (FALSE, TRUE, 1);
4998 demux->index_tables = g_list_prepend (demux->index_tables, t);
5001 /* Store index segment */
5002 g_array_append_val (t->segments, *segment);
5004 /* Check if temporal reordering tables should be pre-calculated */
5005 for (didx = 0; didx < segment->n_delta_entries; didx++) {
5006 MXFDeltaEntry *delta = &segment->delta_entries[didx];
5007 if (delta->pos_table_index == -1) {
5008 if (t->reordered_delta_entry != -1 && didx != t->reordered_delta_entry)
5009 GST_WARNING_OBJECT (demux,
5010 "Index Table specifies more than one stream using temporal reordering (%d and %d)",
5011 didx, t->reordered_delta_entry);
5013 t->reordered_delta_entry = didx;
5014 } else if (delta->pos_table_index > 0)
5015 GST_WARNING_OBJECT (delta,
5016 "Index Table uses fractional offset, please file a bug");
5021 /* Handle temporal offset if present and needed */
5022 for (l = demux->index_tables; l; l = l->next) {
5023 GstMXFDemuxIndexTable *table = l->data;
5026 /* No reordered entries, skip */
5027 if (table->reordered_delta_entry == -1)
5030 GST_DEBUG_OBJECT (demux,
5031 "bodySID:%d indexSID:%d Calculating reverse temporal offset table",
5032 table->body_sid, table->index_sid);
5034 for (segidx = 0; segidx < table->segments->len; segidx++) {
5035 MXFIndexTableSegment *s =
5036 &g_array_index (table->segments, MXFIndexTableSegment, segidx);
5037 guint start = s->index_start_position;
5039 s->index_duration ? start + s->index_duration : start +
5043 if (stop > table->reverse_temporal_offsets->len)
5044 g_array_set_size (table->reverse_temporal_offsets, stop);
5046 for (entidx = 0; entidx < s->n_index_entries; entidx++) {
5047 MXFIndexEntry *entry = &s->index_entries[entidx];
5048 gint8 offs = -entry->temporal_offset;
5049 /* Check we don't exceed boundaries */
5050 if ((start + entidx + entry->temporal_offset) < 0 ||
5051 (start + entidx + entry->temporal_offset) >
5052 table->reverse_temporal_offsets->len) {
5053 GST_ERROR_OBJECT (demux,
5054 "Temporal offset exceeds boundaries. entry:%d offset:%d max:%d",
5055 start + entidx, entry->temporal_offset,
5056 table->reverse_temporal_offsets->len);
5058 /* Applying the temporal offset gives us the entry that should contain this PTS.
5059 * We store the reverse temporal offset on that entry, i.e. the value it should apply
5060 * to go from DTS to PTS. (i.e. entry.pts = entry.dts + rto[idx]) */
5061 g_array_index (table->reverse_temporal_offsets, gint8,
5062 start + entidx + entry->temporal_offset) = offs;
5063 if (entry->temporal_offset > (gint) table->max_temporal_offset) {
5064 GST_LOG_OBJECT (demux,
5065 "Updating max temporal offset to %d (was %d)",
5066 entry->temporal_offset, table->max_temporal_offset);
5067 table->max_temporal_offset = entry->temporal_offset;
5074 g_list_free_full (demux->pending_index_table_segments, g_free);
5075 demux->pending_index_table_segments = NULL;
5077 GST_DEBUG_OBJECT (demux, "Done collecting segments");
5081 gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
5083 GstClockTime keyunit_ts;
5086 GstSeekType start_type, stop_type;
5089 gboolean update, flush, keyframe;
5090 GstSegment seeksegment;
5092 gboolean ret = TRUE;
5095 gst_event_parse_seek (event, &rate, &format, &flags,
5096 &start_type, &start, &stop_type, &stop);
5097 seqnum = gst_event_get_seqnum (event);
5099 if (seqnum == demux->seqnum) {
5100 GST_DEBUG_OBJECT (demux, "Already handled requested seek");
5104 GST_DEBUG_OBJECT (demux, "Seek %" GST_PTR_FORMAT, event);
5106 if (format != GST_FORMAT_TIME)
5112 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
5113 keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
5115 if (!demux->index_table_segments_collected) {
5116 collect_index_table_segments (demux);
5117 demux->index_table_segments_collected = TRUE;
5123 /* Flush start up and downstream to make sure data flow and loops are
5125 e = gst_event_new_flush_start ();
5126 gst_event_set_seqnum (e, seqnum);
5127 gst_mxf_demux_push_src_event (demux, gst_event_ref (e));
5128 gst_pad_push_event (demux->sinkpad, e);
5130 /* Pause the pulling task */
5131 gst_pad_pause_task (demux->sinkpad);
5134 /* Take the stream lock */
5135 GST_PAD_STREAM_LOCK (demux->sinkpad);
5140 /* Stop flushing upstream we need to pull */
5141 e = gst_event_new_flush_stop (TRUE);
5142 gst_event_set_seqnum (e, seqnum);
5143 gst_pad_push_event (demux->sinkpad, e);
5146 /* Work on a copy until we are sure the seek succeeded. */
5147 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
5149 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
5152 /* Apply the seek to our segment */
5153 gst_segment_do_seek (&seeksegment, rate, format, flags,
5154 start_type, start, stop_type, stop, &update);
5156 GST_DEBUG_OBJECT (demux,
5157 "segment initially configured to %" GST_SEGMENT_FORMAT, &seeksegment);
5159 /* Initialize and reset ourselves if needed */
5160 if (flush || seeksegment.position != demux->segment.position) {
5162 if (!demux->metadata_resolved || demux->update_metadata) {
5163 if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
5164 gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
5165 goto unresolved_metadata;
5169 /* Reset all single-track KLV tracking */
5170 for (tmp = demux->partitions; tmp; tmp = tmp->next) {
5171 GstMXFDemuxPartition *partition = (GstMXFDemuxPartition *) tmp->data;
5172 if (partition->single_track) {
5173 partition->clip_klv.consumed = 0;
5178 keyunit_ts = seeksegment.position;
5180 /* Do a first round without changing positions. This is needed to figure out
5181 * the supporting keyframe position (if any) */
5182 for (i = 0; i < demux->src->len; i++) {
5183 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5184 GstMXFDemuxEssenceTrack *etrack;
5185 gint64 track_pos, seeked_pos;
5187 /* Get track and track position for requested time, handles out of bound internally */
5188 if (!gst_mxf_demux_pad_to_track_and_position (demux, p,
5189 seeksegment.position, &etrack, &track_pos))
5190 goto invalid_position;
5193 "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT,
5194 etrack->track_id, etrack->body_sid, etrack->index_sid, track_pos);
5196 /* Find supporting keyframe entry */
5197 seeked_pos = track_pos;
5198 if (gst_mxf_demux_find_essence_element (demux, etrack, &seeked_pos,
5200 /* Couldn't find entry, ignore */
5205 "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT
5206 " entry position %" G_GINT64_FORMAT, etrack->track_id, etrack->body_sid,
5207 etrack->index_sid, track_pos, seeked_pos);
5209 if (seeked_pos != track_pos) {
5210 GstClockTime stream_time;
5211 if (!gst_mxf_demux_pad_get_stream_time (demux, p, etrack, seeked_pos,
5213 goto invalid_position;
5214 GST_LOG_OBJECT (p, "Need to seek to stream time %" GST_TIME_FORMAT,
5215 GST_TIME_ARGS (stream_time));
5216 keyunit_ts = MIN (seeksegment.position, stream_time);
5220 if (keyframe && keyunit_ts != seeksegment.position) {
5221 GST_INFO_OBJECT (demux, "key unit seek, adjusting segment start to "
5222 "%" GST_TIME_FORMAT, GST_TIME_ARGS (keyunit_ts));
5223 gst_segment_do_seek (&seeksegment, rate, format, flags,
5224 start_type, keyunit_ts, stop_type, stop, &update);
5227 /* Finally set the position to the calculated position */
5228 if (flush || keyunit_ts != demux->segment.position) {
5229 guint64 new_offset = -1;
5231 /* Do the actual seeking */
5232 for (i = 0; i < demux->src->len; i++) {
5233 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5237 /* Reset EOS flag on all pads */
5239 gst_mxf_demux_pad_set_position (demux, p, seeksegment.position);
5241 /* we always want to send data starting with a key unit */
5242 position = p->current_essence_track_position;
5244 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
5247 GST_DEBUG_OBJECT (demux, "Unable to find offset for pad %s",
5249 p->current_essence_track_position = p->current_essence_track->duration;
5251 new_offset = MIN (off, new_offset);
5252 if (position != p->current_essence_track_position) {
5254 gst_util_uint64_scale (p->current_essence_track_position -
5256 GST_SECOND * p->current_essence_track->source_track->edit_rate.d,
5257 p->current_essence_track->source_track->edit_rate.n);
5258 p->position_accumulated_error = 0.0;
5259 p->current_material_track_position -=
5260 gst_util_uint64_scale (p->current_essence_track_position -
5262 p->material_track->edit_rate.n *
5263 p->current_essence_track->source_track->edit_rate.d,
5264 p->material_track->edit_rate.d *
5265 p->current_essence_track->source_track->edit_rate.n);
5267 p->current_essence_track_position = position;
5269 p->current_essence_track->position = p->current_essence_track_position;
5272 gst_flow_combiner_reset (demux->flowcombiner);
5273 if (new_offset == -1) {
5274 GST_WARNING_OBJECT (demux, "No new offset found");
5277 demux->offset = new_offset + demux->run_in;
5279 gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
5280 /* Reset the state accordingly */
5281 if (demux->current_partition->single_track
5282 && demux->current_partition->single_track->wrapping !=
5283 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING)
5284 demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
5286 demux->state = GST_MXF_DEMUX_STATE_KLV;
5289 if (G_UNLIKELY (demux->close_seg_event)) {
5290 gst_event_unref (demux->close_seg_event);
5291 demux->close_seg_event = NULL;
5297 /* Stop flushing, the sinks are at time 0 now */
5298 e = gst_event_new_flush_stop (TRUE);
5299 gst_event_set_seqnum (e, seqnum);
5300 gst_mxf_demux_push_src_event (demux, e);
5302 GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
5305 /* Close the current segment for a linear playback */
5306 demux->close_seg_event = gst_event_new_segment (&demux->segment);
5307 gst_event_set_seqnum (demux->close_seg_event, demux->seqnum);
5310 /* Ok seek succeeded, take the newly configured segment */
5311 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
5313 /* Notify about the start of a new segment */
5314 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5317 m = gst_message_new_segment_start (GST_OBJECT (demux),
5318 demux->segment.format, demux->segment.position);
5319 gst_message_set_seqnum (m, seqnum);
5320 gst_element_post_message (GST_ELEMENT (demux), m);
5323 /* Tell all the stream a new segment is needed */
5324 for (i = 0; i < demux->src->len; i++) {
5325 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5326 p->need_segment = TRUE;
5329 for (i = 0; i < demux->essence_tracks->len; i++) {
5330 GstMXFDemuxEssenceTrack *t = g_ptr_array_index (demux->essence_tracks, i);
5334 demux->seqnum = seqnum;
5336 gst_pad_start_task (demux->sinkpad,
5337 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5339 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5346 GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
5351 GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
5354 unresolved_metadata:
5356 gst_pad_start_task (demux->sinkpad,
5357 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5358 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5359 GST_WARNING_OBJECT (demux, "metadata can't be resolved");
5368 /* Stop flushing, the sinks are at time 0 now */
5369 e = gst_event_new_flush_stop (TRUE);
5370 gst_event_set_seqnum (e, seqnum);
5371 gst_mxf_demux_push_src_event (demux, e);
5373 gst_pad_start_task (demux->sinkpad,
5374 (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5375 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5376 GST_WARNING_OBJECT (demux, "Requested seek position is not valid");
5382 gst_mxf_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
5384 GstMXFDemux *demux = GST_MXF_DEMUX (parent);
5387 GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
5389 switch (GST_EVENT_TYPE (event)) {
5390 case GST_EVENT_SEEK:
5391 if (demux->random_access)
5392 ret = gst_mxf_demux_seek_pull (demux, event);
5394 ret = gst_mxf_demux_seek_push (demux, event);
5395 gst_event_unref (event);
5398 ret = gst_pad_push_event (demux->sinkpad, event);
5406 gst_mxf_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
5408 GstMXFDemux *demux = GST_MXF_DEMUX (parent);
5409 gboolean ret = FALSE;
5410 GstMXFDemuxPad *mxfpad = GST_MXF_DEMUX_PAD (pad);
5412 GST_DEBUG_OBJECT (pad, "handling query %s",
5413 gst_query_type_get_name (GST_QUERY_TYPE (query)));
5415 switch (GST_QUERY_TYPE (query)) {
5416 case GST_QUERY_POSITION:
5421 gst_query_parse_position (query, &format, NULL);
5422 if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
5427 GST_FORMAT_DEFAULT ? mxfpad->current_material_track_position :
5430 GST_DEBUG_OBJECT (pad,
5431 "Returning position %" G_GINT64_FORMAT " in format %s", pos,
5432 gst_format_get_name (format));
5434 gst_query_set_position (query, format, pos);
5439 case GST_QUERY_DURATION:{
5443 gst_query_parse_duration (query, &format, NULL);
5444 if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
5447 g_rw_lock_reader_lock (&demux->metadata_lock);
5448 if (!mxfpad->material_track || !mxfpad->material_track->parent.sequence) {
5449 g_rw_lock_reader_unlock (&demux->metadata_lock);
5453 duration = mxfpad->material_track->parent.sequence->duration;
5457 if (duration != -1 && format == GST_FORMAT_TIME) {
5458 if (mxfpad->material_track->edit_rate.n == 0 ||
5459 mxfpad->material_track->edit_rate.d == 0) {
5460 g_rw_lock_reader_unlock (&demux->metadata_lock);
5465 gst_util_uint64_scale (duration,
5466 GST_SECOND * mxfpad->material_track->edit_rate.d,
5467 mxfpad->material_track->edit_rate.n);
5469 g_rw_lock_reader_unlock (&demux->metadata_lock);
5471 GST_DEBUG_OBJECT (pad,
5472 "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
5473 gst_format_get_name (format));
5475 gst_query_set_duration (query, format, duration);
5479 case GST_QUERY_SEEKING:{
5484 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
5485 if (fmt != GST_FORMAT_TIME) {
5486 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5490 if (!gst_pad_query_duration (pad, GST_FORMAT_TIME, &duration)) {
5491 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5495 if (demux->random_access) {
5496 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, duration);
5498 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
5501 seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
5503 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
5505 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, duration);
5507 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
5509 gst_query_unref (peerquery);
5514 case GST_QUERY_SEGMENT:{
5518 format = demux->segment.format;
5521 gst_segment_to_stream_time (&demux->segment, format,
5522 demux->segment.start);
5523 if ((stop = demux->segment.stop) == -1)
5524 stop = demux->segment.duration;
5526 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
5528 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
5533 ret = gst_pad_query_default (pad, parent, query);
5543 GST_DEBUG_OBJECT (pad, "query failed");
5549 gst_mxf_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
5552 GstPadMode mode = GST_PAD_MODE_PUSH;
5554 query = gst_query_new_scheduling ();
5556 if (gst_pad_peer_query (sinkpad, query)) {
5557 if (gst_query_has_scheduling_mode_with_flags (query,
5558 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE)) {
5559 GstSchedulingFlags flags;
5560 gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
5561 if (!(flags & GST_SCHEDULING_FLAG_SEQUENTIAL))
5562 mode = GST_PAD_MODE_PULL;
5565 gst_query_unref (query);
5567 return gst_pad_activate_mode (sinkpad, mode, TRUE);
5571 gst_mxf_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5572 GstPadMode mode, gboolean active)
5576 demux = GST_MXF_DEMUX (parent);
5578 if (mode == GST_PAD_MODE_PUSH) {
5579 demux->random_access = FALSE;
5582 demux->random_access = TRUE;
5583 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_mxf_demux_loop,
5586 demux->random_access = FALSE;
5587 return gst_pad_stop_task (sinkpad);
5595 gst_mxf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
5598 gboolean ret = FALSE;
5600 demux = GST_MXF_DEMUX (parent);
5602 GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
5604 switch (GST_EVENT_TYPE (event)) {
5605 case GST_EVENT_FLUSH_START:
5606 demux->flushing = TRUE;
5607 ret = gst_pad_event_default (pad, parent, event);
5609 case GST_EVENT_FLUSH_STOP:
5610 GST_DEBUG_OBJECT (demux, "flushing queued data in the MXF demuxer");
5612 gst_adapter_clear (demux->adapter);
5613 demux->flushing = FALSE;
5615 ret = gst_pad_event_default (pad, parent, event);
5617 case GST_EVENT_EOS:{
5618 GstMXFDemuxPad *p = NULL;
5621 if (demux->src->len == 0) {
5622 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
5623 ("This stream contains no data."),
5624 ("got eos and didn't find any streams"));
5627 for (i = 0; i < demux->essence_tracks->len; i++) {
5628 GstMXFDemuxEssenceTrack *t =
5629 g_ptr_array_index (demux->essence_tracks, i);
5631 if (t->position > 0)
5632 t->duration = t->position;
5635 for (i = 0; i < demux->src->len; i++) {
5636 GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5639 && p->current_essence_track_position >=
5640 p->current_essence_track->duration) {
5642 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5646 while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
5650 position = p->current_essence_track_position;
5653 gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
5656 GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
5658 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5662 if (gst_pad_push_event (demux->sinkpad,
5663 gst_event_new_seek (demux->segment.rate, GST_FORMAT_BYTES,
5664 demux->segment.flags | GST_SEEK_FLAG_ACCURATE,
5665 GST_SEEK_TYPE_SET, offset + demux->run_in,
5666 GST_SEEK_TYPE_NONE, 0))) {
5668 for (i = 0; i < demux->essence_tracks->len; i++) {
5669 GstMXFDemuxEssenceTrack *etrack =
5670 g_ptr_array_index (demux->essence_tracks, i);
5671 etrack->position = -1;
5676 GST_WARNING_OBJECT (demux,
5677 "Seek to remaining part of the file failed");
5679 gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5684 /* and one more time for good measure apparently? */
5685 gst_pad_event_default (pad, parent, event);
5686 ret = (demux->src->len > 0);
5689 case GST_EVENT_SEGMENT:{
5692 for (i = 0; i < demux->essence_tracks->len; i++) {
5693 GstMXFDemuxEssenceTrack *t =
5694 g_ptr_array_index (demux->essence_tracks, i);
5697 demux->current_partition = NULL;
5698 demux->seqnum = gst_event_get_seqnum (event);
5699 gst_event_unref (event);
5704 ret = gst_pad_event_default (pad, parent, event);
5714 gst_mxf_demux_query (GstElement * element, GstQuery * query)
5716 GstMXFDemux *demux = GST_MXF_DEMUX (element);
5717 gboolean ret = FALSE;
5719 GST_DEBUG_OBJECT (demux, "handling query %s",
5720 gst_query_type_get_name (GST_QUERY_TYPE (query)));
5722 switch (GST_QUERY_TYPE (query)) {
5723 case GST_QUERY_POSITION:
5728 gst_query_parse_position (query, &format, NULL);
5729 if (format != GST_FORMAT_TIME)
5732 pos = demux->segment.position;
5734 GST_DEBUG_OBJECT (demux,
5735 "Returning position %" G_GINT64_FORMAT " in format %s", pos,
5736 gst_format_get_name (format));
5738 gst_query_set_position (query, format, pos);
5743 case GST_QUERY_DURATION:{
5744 gint64 duration = -1;
5748 gst_query_parse_duration (query, &format, NULL);
5749 if (format != GST_FORMAT_TIME)
5752 if (demux->src->len == 0)
5755 g_rw_lock_reader_lock (&demux->metadata_lock);
5756 for (i = 0; i < demux->src->len; i++) {
5757 GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
5760 if (!pad->material_track || !pad->material_track->parent.sequence)
5763 pdur = pad->material_track->parent.sequence->duration;
5764 if (pad->material_track->edit_rate.n == 0 ||
5765 pad->material_track->edit_rate.d == 0 || pdur <= -1)
5769 gst_util_uint64_scale (pdur,
5770 GST_SECOND * pad->material_track->edit_rate.d,
5771 pad->material_track->edit_rate.n);
5772 duration = MAX (duration, pdur);
5774 g_rw_lock_reader_unlock (&demux->metadata_lock);
5776 if (duration == -1) {
5777 GST_DEBUG_OBJECT (demux, "No duration known (yet)");
5781 GST_DEBUG_OBJECT (demux,
5782 "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
5783 gst_format_get_name (format));
5785 gst_query_set_duration (query, format, duration);
5789 case GST_QUERY_SEEKING:{
5793 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
5794 if (fmt != GST_FORMAT_TIME) {
5795 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5799 if (demux->random_access) {
5800 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
5802 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
5805 seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
5807 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
5809 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
5811 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
5813 gst_query_unref (peerquery);
5818 case GST_QUERY_SEGMENT:{
5822 format = demux->segment.format;
5825 gst_segment_to_stream_time (&demux->segment, format,
5826 demux->segment.start);
5827 if ((stop = demux->segment.stop) == -1)
5828 stop = demux->segment.duration;
5830 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
5832 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
5837 /* else forward upstream */
5838 ret = gst_pad_peer_query (demux->sinkpad, query);
5848 GST_DEBUG_OBJECT (demux, "query failed");
5853 static GstStateChangeReturn
5854 gst_mxf_demux_change_state (GstElement * element, GstStateChange transition)
5856 GstMXFDemux *demux = GST_MXF_DEMUX (element);
5857 GstStateChangeReturn ret;
5859 switch (transition) {
5860 case GST_STATE_CHANGE_READY_TO_PAUSED:
5861 demux->seqnum = gst_util_seqnum_next ();
5867 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
5868 if (ret == GST_STATE_CHANGE_FAILURE)
5871 switch (transition) {
5872 case GST_STATE_CHANGE_PAUSED_TO_READY:
5873 gst_mxf_demux_reset (demux);
5883 gst_mxf_demux_set_property (GObject * object, guint prop_id,
5884 const GValue * value, GParamSpec * pspec)
5886 GstMXFDemux *demux = GST_MXF_DEMUX (object);
5890 g_free (demux->requested_package_string);
5891 demux->requested_package_string = g_value_dup_string (value);
5893 case PROP_MAX_DRIFT:
5894 demux->max_drift = g_value_get_uint64 (value);
5897 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5903 gst_mxf_demux_get_property (GObject * object, guint prop_id,
5904 GValue * value, GParamSpec * pspec)
5906 GstMXFDemux *demux = GST_MXF_DEMUX (object);
5910 g_value_set_string (value, demux->current_package_string);
5912 case PROP_MAX_DRIFT:
5913 g_value_set_uint64 (value, demux->max_drift);
5915 case PROP_STRUCTURE:{
5918 g_rw_lock_reader_lock (&demux->metadata_lock);
5919 if (demux->preface &&
5920 MXF_METADATA_BASE (demux->preface)->resolved ==
5921 MXF_METADATA_BASE_RESOLVE_STATE_SUCCESS)
5922 s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
5926 gst_value_set_structure (value, s);
5929 gst_structure_free (s);
5931 g_rw_lock_reader_unlock (&demux->metadata_lock);
5935 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5941 gst_mxf_demux_finalize (GObject * object)
5943 GstMXFDemux *demux = GST_MXF_DEMUX (object);
5945 gst_mxf_demux_reset (demux);
5947 if (demux->adapter) {
5948 g_object_unref (demux->adapter);
5949 demux->adapter = NULL;
5952 if (demux->flowcombiner) {
5953 gst_flow_combiner_free (demux->flowcombiner);
5954 demux->flowcombiner = NULL;
5957 if (demux->close_seg_event) {
5958 gst_event_unref (demux->close_seg_event);
5959 demux->close_seg_event = NULL;
5962 g_free (demux->current_package_string);
5963 demux->current_package_string = NULL;
5964 g_free (demux->requested_package_string);
5965 demux->requested_package_string = NULL;
5967 g_ptr_array_free (demux->src, TRUE);
5969 g_ptr_array_free (demux->essence_tracks, TRUE);
5970 demux->essence_tracks = NULL;
5972 g_hash_table_destroy (demux->metadata);
5974 g_rw_lock_clear (&demux->metadata_lock);
5976 G_OBJECT_CLASS (parent_class)->finalize (object);
5980 gst_mxf_demux_class_init (GstMXFDemuxClass * klass)
5982 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
5983 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
5985 GST_DEBUG_CATEGORY_INIT (mxfdemux_debug, "mxfdemux", 0, "MXF demuxer");
5987 parent_class = g_type_class_peek_parent (klass);
5989 gobject_class->finalize = gst_mxf_demux_finalize;
5990 gobject_class->set_property = gst_mxf_demux_set_property;
5991 gobject_class->get_property = gst_mxf_demux_get_property;
5993 g_object_class_install_property (gobject_class, PROP_PACKAGE,
5994 g_param_spec_string ("package", "Package",
5995 "Material or Source package to use for playback", NULL,
5996 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
5998 g_object_class_install_property (gobject_class, PROP_MAX_DRIFT,
5999 g_param_spec_uint64 ("max-drift", "Maximum drift",
6000 "Maximum number of nanoseconds by which tracks can differ",
6001 100 * GST_MSECOND, G_MAXUINT64, DEFAULT_MAX_DRIFT,
6002 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6004 g_object_class_install_property (gobject_class, PROP_STRUCTURE,
6005 g_param_spec_boxed ("structure", "Structure",
6006 "Structural metadata of the MXF file",
6007 GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6009 gstelement_class->change_state =
6010 GST_DEBUG_FUNCPTR (gst_mxf_demux_change_state);
6011 gstelement_class->query = GST_DEBUG_FUNCPTR (gst_mxf_demux_query);
6013 gst_element_class_add_static_pad_template (gstelement_class,
6014 &mxf_sink_template);
6015 gst_element_class_add_static_pad_template (gstelement_class,
6017 gst_element_class_set_static_metadata (gstelement_class, "MXF Demuxer",
6018 "Codec/Demuxer", "Demux MXF files",
6019 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
6023 gst_mxf_demux_init (GstMXFDemux * demux)
6026 gst_pad_new_from_static_template (&mxf_sink_template, "sink");
6028 gst_pad_set_event_function (demux->sinkpad,
6029 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_event));
6030 gst_pad_set_chain_function (demux->sinkpad,
6031 GST_DEBUG_FUNCPTR (gst_mxf_demux_chain));
6032 gst_pad_set_activate_function (demux->sinkpad,
6033 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate));
6034 gst_pad_set_activatemode_function (demux->sinkpad,
6035 GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_mode));
6037 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
6039 demux->max_drift = DEFAULT_MAX_DRIFT;
6041 demux->adapter = gst_adapter_new ();
6042 demux->flowcombiner = gst_flow_combiner_new ();
6043 g_rw_lock_init (&demux->metadata_lock);
6045 demux->src = g_ptr_array_new ();
6046 demux->essence_tracks = g_ptr_array_new_with_free_func ((GDestroyNotify)
6047 gst_mxf_demux_essence_track_free);
6049 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
6051 gst_mxf_demux_reset (demux);