6caaac8082ff0b4547426389bac83ca8ee7dd5be
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst / mxf / mxfdemux.c
1 /* GStreamer
2  * Copyright (C) 2008-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /**
21  * SECTION:element-mxfdemux
22  * @title: mxfdemux
23  *
24  * mxfdemux demuxes an MXF file into the different contained streams.
25  *
26  * ## Example launch line
27  * |[
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.
30  *
31  */
32
33 /* TODO:
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.
45  *
46  *   - Implement SMPTE D11 essence and the digital cinema/MXF specs
47  */
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include "gstmxfelements.h"
54 #include "mxfdemux.h"
55 #include "mxfessence.h"
56
57 #include <string.h>
58
59 static GstStaticPadTemplate mxf_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
60     GST_PAD_SINK,
61     GST_PAD_ALWAYS,
62     GST_STATIC_CAPS ("application/mxf")
63     );
64
65 static GstStaticPadTemplate mxf_src_template =
66 GST_STATIC_PAD_TEMPLATE ("track_%u",
67     GST_PAD_SRC,
68     GST_PAD_SOMETIMES,
69     GST_STATIC_CAPS_ANY);
70
71 GST_DEBUG_CATEGORY_STATIC (mxfdemux_debug);
72 #define GST_CAT_DEFAULT mxfdemux_debug
73
74 /* Fill klv for the given offset, does not download the data */
75 static GstFlowReturn
76 gst_mxf_demux_peek_klv_packet (GstMXFDemux * demux, guint64 offset,
77     GstMXFKLV * klv);
78
79 /* Ensures the klv data is present. Pulls it if needed */
80 static GstFlowReturn
81 gst_mxf_demux_fill_klv (GstMXFDemux * demux, GstMXFKLV * klv);
82
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);
86
87 static GstFlowReturn
88 gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux, GstMXFKLV * klv);
89
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);
94
95 GType gst_mxf_demux_pad_get_type (void);
96 G_DEFINE_TYPE (GstMXFDemuxPad, gst_mxf_demux_pad, GST_TYPE_PAD);
97
98 static void
99 gst_mxf_demux_pad_finalize (GObject * object)
100 {
101   GstMXFDemuxPad *pad = GST_MXF_DEMUX_PAD (object);
102
103   if (pad->tags) {
104     gst_tag_list_unref (pad->tags);
105     pad->tags = NULL;
106   }
107
108   G_OBJECT_CLASS (gst_mxf_demux_pad_parent_class)->finalize (object);
109 }
110
111 static void
112 gst_mxf_demux_pad_class_init (GstMXFDemuxPadClass * klass)
113 {
114   GObjectClass *gobject_class = (GObjectClass *) klass;
115
116   gobject_class->finalize = gst_mxf_demux_pad_finalize;
117 }
118
119 static void
120 gst_mxf_demux_pad_init (GstMXFDemuxPad * pad)
121 {
122   pad->position = 0;
123   pad->current_material_track_position = 0;
124 }
125
126 #define DEFAULT_MAX_DRIFT 100 * GST_MSECOND
127
128 enum
129 {
130   PROP_0,
131   PROP_PACKAGE,
132   PROP_MAX_DRIFT,
133   PROP_STRUCTURE
134 };
135
136 static gboolean gst_mxf_demux_sink_event (GstPad * pad, GstObject * parent,
137     GstEvent * event);
138 static gboolean gst_mxf_demux_src_event (GstPad * pad, GstObject * parent,
139     GstEvent * event);
140 static gboolean gst_mxf_demux_src_query (GstPad * pad, GstObject * parent,
141     GstQuery * query);
142
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));
147
148 static void
149 gst_mxf_demux_remove_pad (GstMXFDemuxPad * pad, GstMXFDemux * demux)
150 {
151   gst_flow_combiner_remove_pad (demux->flowcombiner, GST_PAD_CAST (pad));
152   gst_element_remove_pad (GST_ELEMENT (demux), GST_PAD_CAST (pad));
153 }
154
155 static void
156 gst_mxf_demux_remove_pads (GstMXFDemux * demux)
157 {
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);
161 }
162
163 static void
164 gst_mxf_demux_partition_free (GstMXFDemuxPartition * partition)
165 {
166   mxf_partition_pack_reset (&partition->partition);
167   mxf_primer_pack_reset (&partition->primer);
168
169   g_free (partition);
170 }
171
172 static void
173 gst_mxf_demux_reset_mxf_state (GstMXFDemux * demux)
174 {
175   guint i;
176
177   GST_DEBUG_OBJECT (demux, "Resetting MXF state");
178
179   g_list_foreach (demux->partitions, (GFunc) gst_mxf_demux_partition_free,
180       NULL);
181   g_list_free (demux->partitions);
182   demux->partitions = NULL;
183
184   demux->current_partition = NULL;
185
186   for (i = 0; i < demux->essence_tracks->len; i++) {
187     GstMXFDemuxEssenceTrack *t =
188         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
189
190     if (t->offsets)
191       g_array_free (t->offsets, TRUE);
192
193     g_free (t->mapping_data);
194
195     if (t->tags)
196       gst_tag_list_unref (t->tags);
197
198     if (t->caps)
199       gst_caps_unref (t->caps);
200   }
201   g_array_set_size (demux->essence_tracks, 0);
202 }
203
204 static void
205 gst_mxf_demux_reset_linked_metadata (GstMXFDemux * demux)
206 {
207   guint i;
208
209   for (i = 0; i < demux->src->len; i++) {
210     GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
211
212     pad->material_track = NULL;
213     pad->material_package = NULL;
214     pad->current_component = NULL;
215   }
216
217   for (i = 0; i < demux->essence_tracks->len; i++) {
218     GstMXFDemuxEssenceTrack *track =
219         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
220
221     track->source_package = NULL;
222     track->delta_id = -1;
223     track->source_track = NULL;
224   }
225
226   demux->current_package = NULL;
227 }
228
229 static void
230 gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
231 {
232   GST_DEBUG_OBJECT (demux, "Resetting metadata");
233
234   g_rw_lock_writer_lock (&demux->metadata_lock);
235
236   demux->update_metadata = TRUE;
237   demux->metadata_resolved = FALSE;
238
239   gst_mxf_demux_reset_linked_metadata (demux);
240
241   demux->preface = NULL;
242
243   if (demux->metadata) {
244     g_hash_table_destroy (demux->metadata);
245   }
246   demux->metadata = mxf_metadata_hash_table_new ();
247
248   if (demux->tags) {
249     gst_tag_list_unref (demux->tags);
250     demux->tags = NULL;
251   }
252
253   g_rw_lock_writer_unlock (&demux->metadata_lock);
254 }
255
256 static void
257 gst_mxf_demux_reset (GstMXFDemux * demux)
258 {
259   GST_DEBUG_OBJECT (demux, "cleaning up MXF demuxer");
260
261   demux->flushing = FALSE;
262
263   demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
264
265   demux->footer_partition_pack_offset = 0;
266   demux->offset = 0;
267
268   demux->pull_footer_metadata = TRUE;
269
270   demux->run_in = -1;
271
272   memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
273
274   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
275
276   if (demux->close_seg_event) {
277     gst_event_unref (demux->close_seg_event);
278     demux->close_seg_event = NULL;
279   }
280
281   gst_adapter_clear (demux->adapter);
282
283   gst_mxf_demux_remove_pads (demux);
284
285   if (demux->random_index_pack) {
286     g_array_free (demux->random_index_pack, TRUE);
287     demux->random_index_pack = NULL;
288   }
289
290   if (demux->pending_index_table_segments) {
291     GList *l;
292
293     for (l = demux->pending_index_table_segments; l; l = l->next) {
294       MXFIndexTableSegment *s = l->data;
295       mxf_index_table_segment_reset (s);
296       g_free (s);
297     }
298     g_list_free (demux->pending_index_table_segments);
299     demux->pending_index_table_segments = NULL;
300   }
301
302   if (demux->index_tables) {
303     GList *l;
304
305     for (l = demux->index_tables; l; l = l->next) {
306       GstMXFDemuxIndexTable *t = l->data;
307       g_array_free (t->segments, TRUE);
308       g_array_free (t->reverse_temporal_offsets, TRUE);
309       g_free (t);
310     }
311     g_list_free (demux->index_tables);
312     demux->index_tables = NULL;
313   }
314
315   demux->index_table_segments_collected = FALSE;
316
317   gst_mxf_demux_reset_mxf_state (demux);
318   gst_mxf_demux_reset_metadata (demux);
319
320   demux->have_group_id = FALSE;
321   demux->group_id = G_MAXUINT;
322 }
323
324 static GstFlowReturn
325 gst_mxf_demux_pull_range (GstMXFDemux * demux, guint64 offset,
326     guint size, GstBuffer ** buffer)
327 {
328   GstFlowReturn ret;
329
330   ret = gst_pad_pull_range (demux->sinkpad, offset, size, buffer);
331   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
332     GST_WARNING_OBJECT (demux,
333         "failed when pulling %u bytes from offset %" G_GUINT64_FORMAT ": %s",
334         size, offset, gst_flow_get_name (ret));
335     *buffer = NULL;
336     return ret;
337   }
338
339   if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
340     GST_WARNING_OBJECT (demux,
341         "partial pull got %" G_GSIZE_FORMAT " when expecting %u from offset %"
342         G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
343     gst_buffer_unref (*buffer);
344     ret = GST_FLOW_EOS;
345     *buffer = NULL;
346     return ret;
347   }
348
349   return ret;
350 }
351
352 static gboolean
353 gst_mxf_demux_push_src_event (GstMXFDemux * demux, GstEvent * event)
354 {
355   gboolean ret = TRUE;
356   guint i;
357
358   GST_DEBUG_OBJECT (demux, "Pushing '%s' event downstream",
359       GST_EVENT_TYPE_NAME (event));
360
361   for (i = 0; i < demux->src->len; i++) {
362     GstMXFDemuxPad *pad = GST_MXF_DEMUX_PAD (g_ptr_array_index (demux->src, i));
363
364     if (pad->eos && GST_EVENT_TYPE (event) == GST_EVENT_EOS)
365       continue;
366
367     ret |= gst_pad_push_event (GST_PAD_CAST (pad), gst_event_ref (event));
368   }
369
370   gst_event_unref (event);
371
372   return ret;
373 }
374
375 static GstMXFDemuxPad *
376 gst_mxf_demux_get_earliest_pad (GstMXFDemux * demux)
377 {
378   guint i;
379   GstClockTime earliest = GST_CLOCK_TIME_NONE;
380   GstMXFDemuxPad *pad = NULL;
381
382   for (i = 0; i < demux->src->len; i++) {
383     GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
384
385     if (!p->eos && p->position < earliest) {
386       earliest = p->position;
387       pad = p;
388     }
389   }
390
391   return pad;
392 }
393
394 static gint
395 gst_mxf_demux_partition_compare (GstMXFDemuxPartition * a,
396     GstMXFDemuxPartition * b)
397 {
398   if (a->partition.this_partition < b->partition.this_partition)
399     return -1;
400   else if (a->partition.this_partition > b->partition.this_partition)
401     return 1;
402   else
403     return 0;
404 }
405
406 /* Final checks and variable calculation for tracks and partition. This function
407  * can be called repeatedly without any side-effect.
408  */
409 static void
410 gst_mxf_demux_partition_postcheck (GstMXFDemux * demux,
411     GstMXFDemuxPartition * partition)
412 {
413   guint i;
414   GstMXFDemuxPartition *old_partition = demux->current_partition;
415
416   /* If we already handled this partition or it doesn't contain any essence, skip */
417   if (partition->single_track || !partition->partition.body_sid)
418     return;
419
420   for (i = 0; i < demux->essence_tracks->len; i++) {
421     GstMXFDemuxEssenceTrack *cand =
422         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
423
424     if (cand->body_sid != partition->partition.body_sid)
425       continue;
426
427     if (!cand->source_package->is_interleaved) {
428       GST_DEBUG_OBJECT (demux,
429           "Assigning single track %d (0x%08x) to partition at offset %"
430           G_GUINT64_FORMAT, cand->track_id, cand->track_number,
431           partition->partition.this_partition);
432
433       partition->single_track = cand;
434
435       if (partition->essence_container_offset != 0
436           && cand->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
437         GstMXFKLV essence_klv;
438         GstMXFDemuxIndex entry;
439         /* Update the essence container offset for the fact that the index
440          * stream offset is relative to the essence position and not to the
441          * KLV position */
442         if (gst_mxf_demux_peek_klv_packet (demux,
443                 partition->partition.this_partition +
444                 partition->essence_container_offset,
445                 &essence_klv) == GST_FLOW_OK) {
446           partition->essence_container_offset += essence_klv.data_offset;
447           /* And keep a copy of the clip/custom klv for this partition */
448           partition->clip_klv = essence_klv;
449           GST_DEBUG_OBJECT (demux,
450               "Non-frame wrapping, updated essence_container_offset to %"
451               G_GUINT64_FORMAT, partition->essence_container_offset);
452
453           /* And match it against index table, this will also update the track delta_id (if needed) */
454           demux->current_partition = partition;
455           find_entry_for_offset (demux, cand,
456               essence_klv.offset + essence_klv.data_offset, &entry);
457           demux->current_partition = old_partition;
458         }
459       }
460
461       break;
462     }
463   }
464 }
465
466 static GstFlowReturn
467 gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, GstMXFKLV * klv)
468 {
469   MXFPartitionPack partition;
470   GList *l;
471   GstMXFDemuxPartition *p = NULL;
472   GstMapInfo map;
473   gboolean ret;
474   GstFlowReturn flowret;
475
476   GST_DEBUG_OBJECT (demux,
477       "Handling partition pack of size %" G_GSIZE_FORMAT " at offset %"
478       G_GUINT64_FORMAT, klv->length, klv->offset);
479
480   for (l = demux->partitions; l; l = l->next) {
481     GstMXFDemuxPartition *tmp = l->data;
482
483     if (tmp->partition.this_partition + demux->run_in == demux->offset &&
484         tmp->partition.major_version == 0x0001) {
485       GST_DEBUG_OBJECT (demux, "Partition already parsed");
486       p = tmp;
487       goto out;
488     }
489   }
490
491   flowret = gst_mxf_demux_fill_klv (demux, klv);
492   if (flowret != GST_FLOW_OK)
493     return flowret;
494
495   gst_buffer_map (klv->data, &map, GST_MAP_READ);
496   ret = mxf_partition_pack_parse (&klv->key, &partition, map.data, map.size);
497   gst_buffer_unmap (klv->data, &map);
498   if (!ret) {
499     GST_ERROR_OBJECT (demux, "Parsing partition pack failed");
500     return GST_FLOW_ERROR;
501   }
502
503   if (partition.this_partition != demux->offset + demux->run_in) {
504     GST_WARNING_OBJECT (demux,
505         "Partition with incorrect offset (this %" G_GUINT64_FORMAT
506         " demux offset %" G_GUINT64_FORMAT " run_in:%" G_GUINT64_FORMAT ")",
507         partition.this_partition, demux->offset, demux->run_in);
508     partition.this_partition = demux->offset + demux->run_in;
509   }
510
511   if (partition.type == MXF_PARTITION_PACK_HEADER)
512     demux->footer_partition_pack_offset = partition.footer_partition;
513
514   for (l = demux->partitions; l; l = l->next) {
515     GstMXFDemuxPartition *tmp = l->data;
516
517     if (tmp->partition.this_partition + demux->run_in == demux->offset) {
518       p = tmp;
519       break;
520     }
521   }
522
523   if (p) {
524     mxf_partition_pack_reset (&p->partition);
525     memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
526   } else {
527     p = g_new0 (GstMXFDemuxPartition, 1);
528     memcpy (&p->partition, &partition, sizeof (MXFPartitionPack));
529     demux->partitions =
530         g_list_insert_sorted (demux->partitions, p,
531         (GCompareFunc) gst_mxf_demux_partition_compare);
532   }
533
534   gst_mxf_demux_partition_postcheck (demux, p);
535
536   for (l = demux->partitions; l; l = l->next) {
537     GstMXFDemuxPartition *a, *b;
538
539     if (l->next == NULL)
540       break;
541
542     a = l->data;
543     b = l->next->data;
544
545     b->partition.prev_partition = a->partition.this_partition;
546   }
547
548 out:
549   GST_DEBUG_OBJECT (demux,
550       "Current partition now %p (body_sid:%d index_sid:%d this_partition:%"
551       G_GUINT64_FORMAT ")", p, p->partition.body_sid, p->partition.index_sid,
552       p->partition.this_partition);
553   demux->current_partition = p;
554
555   return GST_FLOW_OK;
556 }
557
558 static GstFlowReturn
559 gst_mxf_demux_handle_primer_pack (GstMXFDemux * demux, GstMXFKLV * klv)
560 {
561   GstMapInfo map;
562   gboolean ret;
563   GstFlowReturn flowret;
564
565   GST_DEBUG_OBJECT (demux,
566       "Handling primer pack of size %" G_GSIZE_FORMAT " at offset %"
567       G_GUINT64_FORMAT, klv->length, klv->offset);
568
569   if (G_UNLIKELY (!demux->current_partition)) {
570     GST_ERROR_OBJECT (demux, "Primer pack before partition pack");
571     return GST_FLOW_ERROR;
572   }
573
574   if (G_UNLIKELY (demux->current_partition->primer.mappings)) {
575     GST_DEBUG_OBJECT (demux, "Primer pack already exists");
576     return GST_FLOW_OK;
577   }
578
579   flowret = gst_mxf_demux_fill_klv (demux, klv);
580   if (flowret != GST_FLOW_OK)
581     return flowret;
582
583   gst_buffer_map (klv->data, &map, GST_MAP_READ);
584   ret = mxf_primer_pack_parse (&klv->key, &demux->current_partition->primer,
585       map.data, map.size);
586   gst_buffer_unmap (klv->data, &map);
587   if (!ret) {
588     GST_ERROR_OBJECT (demux, "Parsing primer pack failed");
589     return GST_FLOW_ERROR;
590   }
591
592   demux->current_partition->primer.offset = demux->offset;
593
594   return GST_FLOW_OK;
595 }
596
597 static GstFlowReturn
598 gst_mxf_demux_resolve_references (GstMXFDemux * demux)
599 {
600   GstFlowReturn ret = GST_FLOW_OK;
601   GHashTableIter iter;
602   MXFMetadataBase *m = NULL;
603   GstStructure *structure;
604   guint i;
605
606   g_rw_lock_writer_lock (&demux->metadata_lock);
607
608   GST_DEBUG_OBJECT (demux, "Resolve metadata references");
609   demux->update_metadata = FALSE;
610
611   if (!demux->metadata) {
612     GST_ERROR_OBJECT (demux, "No metadata yet");
613     g_rw_lock_writer_unlock (&demux->metadata_lock);
614     return GST_FLOW_ERROR;
615   }
616
617   g_hash_table_iter_init (&iter, demux->metadata);
618   while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
619     m->resolved = MXF_METADATA_BASE_RESOLVE_STATE_NONE;
620   }
621
622   g_hash_table_iter_init (&iter, demux->metadata);
623   while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
624     gboolean resolved;
625
626     resolved = mxf_metadata_base_resolve (m, demux->metadata);
627
628     /* Resolving can fail for anything but the preface, as the preface
629      * will resolve everything required */
630     if (!resolved && MXF_IS_METADATA_PREFACE (m)) {
631       ret = GST_FLOW_ERROR;
632       goto error;
633     }
634   }
635
636   demux->metadata_resolved = TRUE;
637
638   structure =
639       mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
640   if (!demux->tags)
641     demux->tags = gst_tag_list_new_empty ();
642
643   gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_STRUCTURE,
644       structure, NULL);
645
646   gst_structure_free (structure);
647
648   /* Check for quirks */
649   for (i = 0; i < demux->preface->n_identifications; i++) {
650     MXFMetadataIdentification *identification =
651         demux->preface->identifications[i];
652
653     GST_DEBUG_OBJECT (demux, "product:'%s' company:'%s'",
654         identification->product_name, identification->company_name);
655     if (!g_strcmp0 (identification->product_name, "MXFTk Advanced") &&
656         !g_strcmp0 (identification->company_name, "OpenCube") &&
657         identification->product_version.major <= 2 &&
658         identification->product_version.minor <= 0) {
659       GST_WARNING_OBJECT (demux,
660           "Setting up quirk for misuse of temporal_order field");
661       demux->temporal_order_misuse = TRUE;
662     }
663   }
664
665   g_rw_lock_writer_unlock (&demux->metadata_lock);
666
667   return ret;
668
669 error:
670   demux->metadata_resolved = FALSE;
671   g_rw_lock_writer_unlock (&demux->metadata_lock);
672
673   return ret;
674 }
675
676 static MXFMetadataGenericPackage *
677 gst_mxf_demux_find_package (GstMXFDemux * demux, const MXFUMID * umid)
678 {
679   MXFMetadataGenericPackage *ret = NULL;
680   guint i;
681
682   if (demux->preface->content_storage
683       && demux->preface->content_storage->packages) {
684     for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
685       MXFMetadataGenericPackage *p =
686           demux->preface->content_storage->packages[i];
687
688       if (!p)
689         continue;
690
691       if (mxf_umid_is_equal (&p->package_uid, umid)) {
692         ret = p;
693         break;
694       }
695     }
696   }
697
698   return ret;
699 }
700
701 static MXFMetadataGenericPackage *
702 gst_mxf_demux_choose_package (GstMXFDemux * demux)
703 {
704   MXFMetadataGenericPackage *ret = NULL;
705   guint i;
706
707   if (demux->requested_package_string) {
708     MXFUMID umid = { {0,}
709     };
710
711     if (!mxf_umid_from_string (demux->requested_package_string, &umid)) {
712       GST_ERROR_OBJECT (demux, "Invalid requested package");
713     }
714     g_free (demux->requested_package_string);
715     demux->requested_package_string = NULL;
716
717     ret = gst_mxf_demux_find_package (demux, &umid);
718   }
719
720   if (!ret && !mxf_umid_is_zero (&demux->current_package_uid))
721     ret = gst_mxf_demux_find_package (demux, &demux->current_package_uid);
722
723   if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
724           || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
725               && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
726     goto done;
727   else if (ret)
728     GST_WARNING_OBJECT (demux,
729         "Current package is not a material package or top-level source package, choosing the first best");
730   else if (!mxf_umid_is_zero (&demux->current_package_uid))
731     GST_WARNING_OBJECT (demux,
732         "Current package not found, choosing the first best");
733
734   ret = demux->preface->primary_package;
735   if (ret && (MXF_IS_METADATA_MATERIAL_PACKAGE (ret)
736           || (MXF_IS_METADATA_SOURCE_PACKAGE (ret)
737               && MXF_METADATA_SOURCE_PACKAGE (ret)->top_level)))
738     goto done;
739   ret = NULL;
740
741   for (i = 0; i < demux->preface->content_storage->n_packages; i++) {
742     if (demux->preface->content_storage->packages[i] &&
743         MXF_IS_METADATA_MATERIAL_PACKAGE (demux->preface->content_storage->
744             packages[i])) {
745       ret =
746           MXF_METADATA_GENERIC_PACKAGE (demux->preface->content_storage->
747           packages[i]);
748       break;
749     }
750   }
751
752   if (!ret) {
753     GST_ERROR_OBJECT (demux, "No material package");
754     return NULL;
755   }
756
757 done:
758   if (mxf_umid_is_equal (&ret->package_uid, &demux->current_package_uid)) {
759     gchar current_package_string[96];
760
761     gst_mxf_demux_remove_pads (demux);
762     memcpy (&demux->current_package_uid, &ret->package_uid, 32);
763
764     mxf_umid_to_string (&ret->package_uid, current_package_string);
765     demux->current_package_string = g_strdup (current_package_string);
766     g_object_notify (G_OBJECT (demux), "package");
767
768     if (!demux->tags)
769       demux->tags = gst_tag_list_new_empty ();
770     gst_tag_list_add (demux->tags, GST_TAG_MERGE_REPLACE, GST_TAG_MXF_UMID,
771         demux->current_package_string, NULL);
772   }
773   demux->current_package = ret;
774
775   return ret;
776 }
777
778 static GstFlowReturn
779 gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux)
780 {
781   guint i, j, k;
782
783   g_return_val_if_fail (demux->preface->content_storage, GST_FLOW_ERROR);
784   g_return_val_if_fail (demux->preface->content_storage->essence_container_data,
785       GST_FLOW_ERROR);
786
787   for (i = 0; i < demux->preface->content_storage->n_essence_container_data;
788       i++) {
789     MXFMetadataEssenceContainerData *edata;
790     MXFMetadataSourcePackage *package;
791     MXFFraction common_rate = { 0, 0 };
792
793     if (demux->preface->content_storage->essence_container_data[i] == NULL)
794       continue;
795
796     edata = demux->preface->content_storage->essence_container_data[i];
797
798     if (!edata->linked_package) {
799       GST_WARNING_OBJECT (demux, "Linked package not resolved");
800       continue;
801     }
802
803     package = edata->linked_package;
804
805     if (!package->parent.tracks) {
806       GST_WARNING_OBJECT (demux, "Linked package with no resolved tracks");
807       continue;
808     }
809
810     for (j = 0; j < package->parent.n_tracks; j++) {
811       MXFMetadataTimelineTrack *track;
812       GstMXFDemuxEssenceTrack *etrack = NULL;
813       GstCaps *caps = NULL;
814       gboolean new = FALSE;
815
816       if (!package->parent.tracks[j]
817           || !MXF_IS_METADATA_TIMELINE_TRACK (package->parent.tracks[j])) {
818         GST_DEBUG_OBJECT (demux,
819             "Skipping non-timeline track (id:%d number:0x%08x)",
820             package->parent.tracks[j]->track_id,
821             package->parent.tracks[j]->track_number);
822         continue;
823       }
824
825       track = MXF_METADATA_TIMELINE_TRACK (package->parent.tracks[j]);
826       if ((track->parent.type & 0xf0) != 0x30) {
827         GST_DEBUG_OBJECT (demux,
828             "Skipping track of type 0x%02x (id:%d number:0x%08x)",
829             track->parent.type, track->parent.track_id,
830             track->parent.track_number);
831         continue;
832       }
833
834       if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0) {
835         GST_WARNING_OBJECT (demux, "Invalid edit rate");
836         continue;
837       }
838
839       if (package->is_interleaved) {
840         /*
841          * S377-1:2019 "9.4.2 The MXF timing model"
842          *
843          * The value of Edit Rate shall be identical for every timeline Essence
844          * Track of the Top-Level File Package.
845          *
846          * The value of Edit Rate of the timeline Essence Tracks of one
847          * Top-Level File Package need not match the Edit Rate of the Essence
848          * Tracks of the other Top-Level File Packages.
849          *
850          * S377-1:2019 "9.5.5 Top-Level File Packages"
851          *
852          *12. All Essence Tracks of a Top-Level File Package **shall** have the
853          *    same value of Edit Rate. All other Tracks of a Top-Level File
854          *    Package **should** have the same value of Edit Rate as the
855          *    Essence Tracks.
856          */
857         if (common_rate.n == 0 && common_rate.d == 0) {
858           common_rate = track->edit_rate;
859         } else if (common_rate.n * track->edit_rate.d !=
860             common_rate.d * track->edit_rate.n) {
861           GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
862               ("Interleaved File Package doesn't have identical edit rate on all tracks."));
863           return GST_FLOW_ERROR;
864         }
865       }
866
867       for (k = 0; k < demux->essence_tracks->len; k++) {
868         GstMXFDemuxEssenceTrack *tmp =
869             &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
870             k);
871
872         if (tmp->track_number == track->parent.track_number &&
873             tmp->body_sid == edata->body_sid) {
874           if (tmp->track_id != track->parent.track_id ||
875               !mxf_umid_is_equal (&tmp->source_package_uid,
876                   &package->parent.package_uid)) {
877             GST_ERROR_OBJECT (demux, "There already exists a different track "
878                 "with this track number and body sid but a different source "
879                 "or source track id -- ignoring");
880             continue;
881           }
882           etrack = tmp;
883           break;
884         }
885       }
886
887       if (!etrack) {
888         GstMXFDemuxEssenceTrack tmp;
889
890         memset (&tmp, 0, sizeof (tmp));
891         tmp.body_sid = edata->body_sid;
892         tmp.index_sid = edata->index_sid;
893         tmp.track_number = track->parent.track_number;
894         tmp.track_id = track->parent.track_id;
895         memcpy (&tmp.source_package_uid, &package->parent.package_uid, 32);
896
897         if (demux->current_partition->partition.body_sid == edata->body_sid &&
898             demux->current_partition->partition.body_offset == 0)
899           tmp.position = 0;
900         else
901           tmp.position = -1;
902
903         g_array_append_val (demux->essence_tracks, tmp);
904         etrack =
905             &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
906             demux->essence_tracks->len - 1);
907         new = TRUE;
908       }
909
910       etrack->source_package = NULL;
911       etrack->source_track = NULL;
912       etrack->delta_id = -1;
913
914       if (!track->parent.sequence) {
915         GST_WARNING_OBJECT (demux, "Source track has no sequence");
916         goto next;
917       }
918
919       if (track->parent.n_descriptor == 0) {
920         GST_WARNING_OBJECT (demux, "Source track has no descriptors");
921         goto next;
922       }
923
924       if (track->parent.sequence->duration > etrack->duration)
925         etrack->duration = track->parent.sequence->duration;
926
927       g_free (etrack->mapping_data);
928       etrack->mapping_data = NULL;
929       etrack->handler = NULL;
930       etrack->handle_func = NULL;
931       if (etrack->tags)
932         gst_tag_list_unref (etrack->tags);
933       etrack->tags = NULL;
934
935       etrack->handler = mxf_essence_element_handler_find (track);
936       if (!etrack->handler) {
937         gchar essence_container[48];
938         gchar essence_compression[48];
939         gchar *name;
940
941         GST_WARNING_OBJECT (demux,
942             "No essence element handler for track %u found", i);
943
944         mxf_ul_to_string (&track->parent.descriptor[0]->essence_container,
945             essence_container);
946
947         if (track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE) {
948           if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->parent.
949                   descriptor[0]))
950             mxf_ul_to_string (&MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR
951                 (track->parent.descriptor[0])->picture_essence_coding,
952                 essence_compression);
953
954           name =
955               g_strdup_printf ("video/x-mxf-%s-%s", essence_container,
956               essence_compression);
957         } else if (track->parent.type == MXF_METADATA_TRACK_SOUND_ESSENCE) {
958           if (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track->parent.
959                   descriptor[0]))
960             mxf_ul_to_string (&MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR
961                 (track->parent.descriptor[0])->sound_essence_compression,
962                 essence_compression);
963
964           name =
965               g_strdup_printf ("audio/x-mxf-%s-%s", essence_container,
966               essence_compression);
967         } else if (track->parent.type == MXF_METADATA_TRACK_DATA_ESSENCE) {
968           if (MXF_IS_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (track->parent.
969                   descriptor[0]))
970             mxf_ul_to_string (&MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR
971                 (track->parent.descriptor[0])->data_essence_coding,
972                 essence_compression);
973
974           name =
975               g_strdup_printf ("application/x-mxf-%s-%s", essence_container,
976               essence_compression);
977         } else {
978           name = NULL;
979           g_assert_not_reached ();
980         }
981
982         caps = gst_caps_new_empty_simple (name);
983         g_free (name);
984         etrack->intra_only = FALSE;
985       } else {
986         caps =
987             etrack->handler->create_caps (track, &etrack->tags,
988             &etrack->intra_only, &etrack->handle_func, &etrack->mapping_data);
989       }
990
991       GST_DEBUG_OBJECT (demux, "Created caps %" GST_PTR_FORMAT, caps);
992
993       if (!caps && new) {
994         GST_WARNING_OBJECT (demux, "No caps created, ignoring stream");
995         g_free (etrack->mapping_data);
996         etrack->mapping_data = NULL;
997         if (etrack->tags)
998           gst_tag_list_unref (etrack->tags);
999         etrack->tags = NULL;
1000         goto next;
1001       } else if (!caps) {
1002         GST_WARNING_OBJECT (demux, "Couldn't create updated caps for stream");
1003       } else if (!etrack->caps || !gst_caps_is_equal (etrack->caps, caps)) {
1004         if (etrack->caps)
1005           gst_caps_unref (etrack->caps);
1006         etrack->caps = caps;
1007       } else {
1008         gst_caps_unref (caps);
1009         caps = NULL;
1010       }
1011
1012       etrack->min_edit_units = 1;
1013       /* Ensure we don't output one buffer per sample for audio */
1014       if (gst_util_uint64_scale (GST_SECOND, track->edit_rate.d,
1015               track->edit_rate.n) < 10 * GST_MSECOND) {
1016         GstStructure *s = gst_caps_get_structure (etrack->caps, 0);
1017         const gchar *name = gst_structure_get_name (s);
1018         if (g_str_has_prefix (name, "audio/x-raw")) {
1019           etrack->min_edit_units =
1020               gst_util_uint64_scale (25 * GST_MSECOND, track->edit_rate.n,
1021               track->edit_rate.d * GST_SECOND);
1022           GST_DEBUG_OBJECT (demux, "Seting miminum number of edit units to %u",
1023               etrack->min_edit_units);
1024         }
1025       }
1026
1027       /* FIXME : We really should just abort/ignore the stream completely if we
1028        * don't have a handler for it */
1029       if (etrack->handler != NULL)
1030         etrack->wrapping = etrack->handler->get_track_wrapping (track);
1031       else
1032         etrack->wrapping = MXF_ESSENCE_WRAPPING_UNKNOWN_WRAPPING;
1033
1034       if (package->is_interleaved) {
1035         GST_DEBUG_OBJECT (demux,
1036             "track comes from interleaved source package with %d track(s), setting delta_id to -1",
1037             package->parent.n_tracks);
1038         if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
1039           GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1040               ("Non-frame-wrapping is not allowed in interleaved File Package."));
1041           return GST_FLOW_ERROR;
1042         }
1043         etrack->delta_id = MXF_INDEX_DELTA_ID_UNKNOWN;
1044       } else {
1045         etrack->delta_id = MXF_INDEX_DELTA_ID_UNKNOWN;
1046       }
1047       etrack->source_package = package;
1048       etrack->source_track = track;
1049       continue;
1050
1051     next:
1052       if (new) {
1053         g_free (etrack->mapping_data);
1054         if (etrack->tags)
1055           gst_tag_list_unref (etrack->tags);
1056         if (etrack->caps)
1057           gst_caps_unref (etrack->caps);
1058
1059         g_array_remove_index (demux->essence_tracks,
1060             demux->essence_tracks->len - 1);
1061       }
1062     }
1063   }
1064
1065   if (demux->essence_tracks->len == 0) {
1066     GST_ERROR_OBJECT (demux, "No valid essence tracks in this file");
1067     return GST_FLOW_ERROR;
1068   }
1069
1070   for (i = 0; i < demux->essence_tracks->len; i++) {
1071     GstMXFDemuxEssenceTrack *etrack =
1072         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
1073
1074     if (!etrack->source_package || !etrack->source_track || !etrack->caps) {
1075       GST_ERROR_OBJECT (demux, "Failed to update essence track %u", i);
1076       return GST_FLOW_ERROR;
1077     }
1078
1079   }
1080
1081   return GST_FLOW_OK;
1082 }
1083
1084 static MXFMetadataEssenceContainerData *
1085 essence_container_for_source_package (MXFMetadataContentStorage * storage,
1086     MXFMetadataSourcePackage * package)
1087 {
1088   guint i;
1089
1090   for (i = 0; i < storage->n_essence_container_data; i++) {
1091     MXFMetadataEssenceContainerData *cont = storage->essence_container_data[i];
1092     if (cont && cont->linked_package == package)
1093       return cont;
1094   }
1095
1096   return NULL;
1097 }
1098
1099 static void
1100 gst_mxf_demux_show_topology (GstMXFDemux * demux)
1101 {
1102   GList *material_packages = NULL;
1103   GList *file_packages = NULL;
1104   GList *tmp;
1105   MXFMetadataContentStorage *storage = demux->preface->content_storage;
1106   guint i;
1107   gchar str[96];
1108
1109   /* Show the topology starting from the preface */
1110   GST_DEBUG_OBJECT (demux, "Topology");
1111
1112   for (i = 0; i < storage->n_packages; i++) {
1113     MXFMetadataGenericPackage *pack = storage->packages[i];
1114     if (MXF_IS_METADATA_MATERIAL_PACKAGE (pack))
1115       material_packages = g_list_append (material_packages, pack);
1116     else if (MXF_IS_METADATA_SOURCE_PACKAGE (pack))
1117       file_packages = g_list_append (file_packages, pack);
1118     else
1119       GST_DEBUG_OBJECT (demux, "Unknown package type");
1120   }
1121
1122   GST_DEBUG_OBJECT (demux, "Number of Material Package (i.e. output) : %d",
1123       g_list_length (material_packages));
1124   for (tmp = material_packages; tmp; tmp = tmp->next) {
1125     MXFMetadataMaterialPackage *pack = (MXFMetadataMaterialPackage *) tmp->data;
1126     GST_DEBUG_OBJECT (demux, "  Package with %d tracks , UID:%s",
1127         pack->n_tracks, mxf_umid_to_string (&pack->package_uid, str));
1128     for (i = 0; i < pack->n_tracks; i++) {
1129       MXFMetadataTrack *track = pack->tracks[i];
1130       if (track == NULL) {
1131         GST_DEBUG_OBJECT (demux, "    Unknown/Unhandled track UUID %s",
1132             mxf_uuid_to_string (&pack->tracks_uids[i], str));
1133       } else if (MXF_IS_METADATA_TIMELINE_TRACK (track)) {
1134         MXFMetadataTimelineTrack *mtrack = (MXFMetadataTimelineTrack *) track;
1135         GST_DEBUG_OBJECT (demux,
1136             "    Timeline Track id:%d number:0x%08x name:`%s` edit_rate:%d/%d origin:%"
1137             G_GINT64_FORMAT, track->track_id, track->track_number,
1138             track->track_name, mtrack->edit_rate.n, mtrack->edit_rate.d,
1139             mtrack->origin);
1140       } else {
1141         GST_DEBUG_OBJECT (demux,
1142             "    Non-Timeline-Track id:%d number:0x%08x name:`%s`",
1143             track->track_id, track->track_number, track->track_name);
1144       }
1145       if (track) {
1146         MXFMetadataSequence *sequence = track->sequence;
1147         guint si;
1148         GST_DEBUG_OBJECT (demux,
1149             "      Sequence duration:%" G_GINT64_FORMAT
1150             " n_structural_components:%d", sequence->duration,
1151             sequence->n_structural_components);
1152         for (si = 0; si < sequence->n_structural_components; si++) {
1153           MXFMetadataStructuralComponent *comp =
1154               sequence->structural_components[si];
1155           GST_DEBUG_OBJECT (demux,
1156               "        Component #%d duration:%" G_GINT64_FORMAT, si,
1157               comp->duration);
1158           if (MXF_IS_METADATA_SOURCE_CLIP (comp)) {
1159             MXFMetadataSourceClip *clip = (MXFMetadataSourceClip *) comp;
1160             GST_DEBUG_OBJECT (demux,
1161                 "          Clip start_position:%" G_GINT64_FORMAT
1162                 " source_track_id:%d source_package_id:%s",
1163                 clip->start_position, clip->source_track_id,
1164                 mxf_umid_to_string (&clip->source_package_id, str));
1165           }
1166         }
1167
1168       }
1169     }
1170   }
1171
1172   GST_DEBUG_OBJECT (demux, "Number of File Packages (i.e. input) : %d",
1173       g_list_length (file_packages));
1174   for (tmp = file_packages; tmp; tmp = tmp->next) {
1175     MXFMetadataMaterialPackage *pack = (MXFMetadataMaterialPackage *) tmp->data;
1176     MXFMetadataSourcePackage *src = (MXFMetadataSourcePackage *) pack;
1177     MXFMetadataEssenceContainerData *econt =
1178         essence_container_for_source_package (storage, src);
1179     GST_DEBUG_OBJECT (demux,
1180         "  Package (body_sid:%d index_sid:%d top_level:%d) with %d tracks , UID:%s",
1181         econt->body_sid, econt->index_sid, src->top_level, pack->n_tracks,
1182         mxf_umid_to_string (&pack->package_uid, str));
1183     GST_DEBUG_OBJECT (demux, "    Package descriptor : %s",
1184         g_type_name (G_OBJECT_TYPE (src->descriptor)));
1185     for (i = 0; i < pack->n_tracks; i++) {
1186       MXFMetadataTrack *track = pack->tracks[i];
1187       MXFMetadataSequence *sequence = track->sequence;
1188       guint di, si;
1189       if (MXF_IS_METADATA_TIMELINE_TRACK (track)) {
1190         MXFMetadataTimelineTrack *mtrack = (MXFMetadataTimelineTrack *) track;
1191         GST_DEBUG_OBJECT (demux,
1192             "    Timeline Track id:%d number:0x%08x name:`%s` edit_rate:%d/%d origin:%"
1193             G_GINT64_FORMAT, track->track_id, track->track_number,
1194             track->track_name, mtrack->edit_rate.n, mtrack->edit_rate.d,
1195             mtrack->origin);
1196       } else {
1197         GST_DEBUG_OBJECT (demux,
1198             "    Non-Timeline-Track id:%d number:0x%08x name:`%s` type:0x%x",
1199             track->track_id, track->track_number, track->track_name,
1200             track->type);
1201       }
1202       for (di = 0; di < track->n_descriptor; di++) {
1203         MXFMetadataFileDescriptor *desc = track->descriptor[di];
1204         GST_DEBUG_OBJECT (demux, "      Descriptor %s %s",
1205             g_type_name (G_OBJECT_TYPE (desc)),
1206             mxf_ul_to_string (&desc->essence_container, str));
1207       }
1208       GST_DEBUG_OBJECT (demux,
1209           "      Sequence duration:%" G_GINT64_FORMAT
1210           " n_structural_components:%d", sequence->duration,
1211           sequence->n_structural_components);
1212       for (si = 0; si < sequence->n_structural_components; si++) {
1213         MXFMetadataStructuralComponent *comp =
1214             sequence->structural_components[si];
1215         GST_DEBUG_OBJECT (demux,
1216             "        Component #%d duration:%" G_GINT64_FORMAT, si,
1217             comp->duration);
1218       }
1219     }
1220   }
1221
1222   g_list_free (material_packages);
1223   g_list_free (file_packages);
1224 }
1225
1226 static GstFlowReturn
1227 gst_mxf_demux_update_tracks (GstMXFDemux * demux)
1228 {
1229   MXFMetadataGenericPackage *current_package = NULL;
1230   guint i, j, k;
1231   gboolean first_run;
1232   guint component_index;
1233   GstFlowReturn ret;
1234   GList *pads = NULL, *l;
1235   GstVideoTimeCode start_timecode = GST_VIDEO_TIME_CODE_INIT;
1236
1237   g_rw_lock_writer_lock (&demux->metadata_lock);
1238   GST_DEBUG_OBJECT (demux, "Updating tracks");
1239
1240   gst_mxf_demux_show_topology (demux);
1241
1242   if ((ret = gst_mxf_demux_update_essence_tracks (demux)) != GST_FLOW_OK) {
1243     goto error;
1244   }
1245
1246   current_package = gst_mxf_demux_choose_package (demux);
1247
1248   if (!current_package) {
1249     GST_ERROR_OBJECT (demux, "Unable to find current package");
1250     ret = GST_FLOW_ERROR;
1251     goto error;
1252   } else if (!current_package->tracks) {
1253     GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks");
1254     ret = GST_FLOW_ERROR;
1255     goto error;
1256   } else if (!current_package->n_essence_tracks) {
1257     GST_ERROR_OBJECT (demux, "Current package has no essence tracks");
1258     ret = GST_FLOW_ERROR;
1259     goto error;
1260   }
1261
1262   first_run = (demux->src->len == 0);
1263
1264   /* For material packages, there must be one timecode track with one
1265    * continuous timecode. For source packages there might be multiple,
1266    * discontinuous timecode components.
1267    * TODO: Support multiple timecode components
1268    */
1269   for (i = 0; i < current_package->n_tracks; i++) {
1270     MXFMetadataTimelineTrack *track = NULL;
1271     MXFMetadataSequence *sequence = NULL;
1272     MXFMetadataTimecodeComponent *component = NULL;
1273
1274     if (!current_package->tracks[i]) {
1275       GST_WARNING_OBJECT (demux, "Unresolved track");
1276       continue;
1277     }
1278
1279     if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
1280       GST_DEBUG_OBJECT (demux, "Skipping Non-timeline track");
1281       continue;
1282     }
1283
1284
1285     track = MXF_METADATA_TIMELINE_TRACK (current_package->tracks[i]);
1286
1287     if (!track->parent.sequence)
1288       continue;
1289     sequence = track->parent.sequence;
1290     if (sequence->n_structural_components != 1 ||
1291         !sequence->structural_components[0]
1292         ||
1293         !MXF_IS_METADATA_TIMECODE_COMPONENT (sequence->structural_components
1294             [0]))
1295       continue;
1296
1297     component =
1298         MXF_METADATA_TIMECODE_COMPONENT (sequence->structural_components[0]);
1299
1300     /* Not a timecode track */
1301     if (track->parent.type && (track->parent.type & 0xf0) != 0x10)
1302       continue;
1303
1304     /* Main timecode track must have id 1, all others must be 0 */
1305     if (track->parent.track_id != 1)
1306       continue;
1307
1308     gst_video_time_code_init (&start_timecode, track->edit_rate.n,
1309         track->edit_rate.d, NULL, (component->drop_frame
1310             ?
1311             GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME
1312             : GST_VIDEO_TIME_CODE_FLAGS_NONE), 0, 0, 0, 0, 0);
1313     gst_video_time_code_add_frames (&start_timecode, track->origin);
1314     gst_video_time_code_add_frames (&start_timecode, component->start_timecode);
1315     break;
1316   }
1317
1318   for (i = 0; i < current_package->n_tracks; i++) {
1319     MXFMetadataTimelineTrack *track = NULL;
1320     MXFMetadataSequence *sequence;
1321     MXFMetadataSourceClip *component = NULL;
1322     MXFMetadataSourcePackage *source_package = NULL;
1323     MXFMetadataTimelineTrack *source_track = NULL;
1324     GstMXFDemuxEssenceTrack *etrack = NULL;
1325     GstMXFDemuxPad *pad = NULL;
1326     GstCaps *pad_caps;
1327
1328     GST_DEBUG_OBJECT (demux, "Handling track %u", i);
1329
1330     if (!current_package->tracks[i]) {
1331       GST_WARNING_OBJECT (demux, "Unresolved track");
1332       continue;
1333     }
1334
1335     if (!MXF_IS_METADATA_TIMELINE_TRACK (current_package->tracks[i])) {
1336       GST_DEBUG_OBJECT (demux, "No timeline track");
1337       continue;
1338     }
1339
1340     track = MXF_METADATA_TIMELINE_TRACK (current_package->tracks[i]);
1341
1342     if (!first_run) {
1343       /* Find pad from track_id */
1344       for (j = 0; j < demux->src->len; j++) {
1345         GstMXFDemuxPad *tmp = g_ptr_array_index (demux->src, j);
1346
1347         if (tmp->track_id == track->parent.track_id) {
1348           pad = tmp;
1349           break;
1350         }
1351       }
1352     }
1353
1354     if (pad)
1355       component_index = pad->current_component_index;
1356     else
1357       component_index = 0;
1358
1359     if (!track->parent.sequence) {
1360       GST_WARNING_OBJECT (demux, "Track with no sequence");
1361       if (!pad) {
1362         continue;
1363       } else {
1364         ret = GST_FLOW_ERROR;
1365         goto error;
1366       }
1367     }
1368
1369     sequence = track->parent.sequence;
1370
1371     if (MXF_IS_METADATA_SOURCE_PACKAGE (current_package)) {
1372       GST_DEBUG_OBJECT (demux, "Playing source package");
1373
1374       component = NULL;
1375       source_package = MXF_METADATA_SOURCE_PACKAGE (current_package);
1376       source_track = track;
1377     } else if (sequence->structural_components
1378         &&
1379         MXF_IS_METADATA_SOURCE_CLIP (sequence->structural_components
1380             [component_index])) {
1381       GST_DEBUG_OBJECT (demux, "Playing material package");
1382
1383       component =
1384           MXF_METADATA_SOURCE_CLIP (sequence->structural_components
1385           [component_index]);
1386       if (!component) {
1387         GST_WARNING_OBJECT (demux, "NULL component in non-source package");
1388         if (!pad) {
1389           continue;
1390         } else {
1391           ret = GST_FLOW_ERROR;
1392           goto error;
1393         }
1394       }
1395
1396       if (component->source_package && component->source_package->top_level &&
1397           MXF_METADATA_GENERIC_PACKAGE (component->source_package)->tracks) {
1398         MXFMetadataGenericPackage *tmp_pkg =
1399             MXF_METADATA_GENERIC_PACKAGE (component->source_package);
1400
1401         source_package = component->source_package;
1402
1403         for (k = 0; k < tmp_pkg->n_tracks; k++) {
1404           MXFMetadataTrack *tmp = tmp_pkg->tracks[k];
1405
1406           if (tmp->track_id == component->source_track_id) {
1407             source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1408             break;
1409           }
1410         }
1411       }
1412     }
1413
1414     if (track->parent.type && (track->parent.type & 0xf0) != 0x30) {
1415       GST_DEBUG_OBJECT (demux,
1416           "No essence track. type:0x%02x track_id:%d track_number:0x%08x",
1417           track->parent.type, track->parent.track_id,
1418           track->parent.track_number);
1419       if (!pad) {
1420         continue;
1421       } else {
1422         ret = GST_FLOW_ERROR;
1423         goto error;
1424       }
1425     }
1426
1427     if (!source_package || track->parent.type == MXF_METADATA_TRACK_UNKNOWN
1428         || !source_track) {
1429       GST_WARNING_OBJECT (demux,
1430           "No source package or track type for track found");
1431       if (!pad) {
1432         continue;
1433       } else {
1434         ret = GST_FLOW_ERROR;
1435         goto error;
1436       }
1437     }
1438
1439     for (k = 0; k < demux->essence_tracks->len; k++) {
1440       GstMXFDemuxEssenceTrack *tmp =
1441           &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, k);
1442
1443       if (tmp->source_package == source_package &&
1444           tmp->source_track == source_track) {
1445         etrack = tmp;
1446         break;
1447       }
1448     }
1449
1450     if (!etrack) {
1451       GST_WARNING_OBJECT (demux, "No essence track for this track found");
1452       if (!pad) {
1453         continue;
1454       } else {
1455         ret = GST_FLOW_ERROR;
1456         goto error;
1457       }
1458     }
1459
1460     if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0 ||
1461         source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1462       GST_WARNING_OBJECT (demux, "Track has an invalid edit rate");
1463       if (!pad) {
1464         continue;
1465       } else {
1466         ret = GST_FLOW_ERROR;
1467         goto error;
1468       }
1469     }
1470
1471     if (MXF_IS_METADATA_MATERIAL_PACKAGE (current_package) && !component) {
1472       GST_WARNING_OBJECT (demux,
1473           "Playing material package but found no component for track");
1474       if (!pad) {
1475         continue;
1476       } else {
1477         ret = GST_FLOW_ERROR;
1478         goto error;
1479       }
1480     }
1481
1482     if (!source_package->descriptor) {
1483       GST_WARNING_OBJECT (demux, "Source package has no descriptors");
1484       if (!pad) {
1485         continue;
1486       } else {
1487         ret = GST_FLOW_ERROR;
1488         goto error;
1489       }
1490     }
1491
1492     if (!source_track->parent.descriptor) {
1493       GST_WARNING_OBJECT (demux, "No descriptor found for track");
1494       if (!pad) {
1495         continue;
1496       } else {
1497         ret = GST_FLOW_ERROR;
1498         goto error;
1499       }
1500     }
1501
1502     if (!pad && first_run) {
1503       GstPadTemplate *templ;
1504       gchar *pad_name;
1505
1506       templ =
1507           gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
1508           "track_%u");
1509       pad_name = g_strdup_printf ("track_%u", track->parent.track_id);
1510
1511       g_assert (templ != NULL);
1512
1513       /* Create pad */
1514       pad = (GstMXFDemuxPad *) g_object_new (GST_TYPE_MXF_DEMUX_PAD,
1515           "name", pad_name, "direction", GST_PAD_SRC, "template", templ, NULL);
1516       pad->need_segment = TRUE;
1517       pad->eos = FALSE;
1518       g_free (pad_name);
1519
1520       if (demux->tags)
1521         pad->tags = gst_tag_list_copy (demux->tags);
1522     }
1523
1524     if (!pad) {
1525       GST_WARNING_OBJECT (demux,
1526           "Not the first pad addition run, ignoring new track");
1527       continue;
1528     }
1529
1530     /* Update pad */
1531     pad->track_id = track->parent.track_id;
1532
1533     pad->material_package = current_package;
1534     pad->material_track = track;
1535
1536     pad->start_timecode = start_timecode;
1537
1538     /* If we just added the pad initialize for the current component */
1539     if (first_run && MXF_IS_METADATA_MATERIAL_PACKAGE (current_package)) {
1540       pad->current_component_index = 0;
1541       pad->current_component_start = source_track->origin;
1542       pad->current_component_start_position = 0;
1543
1544       if (component->parent.duration >= -1)
1545         pad->current_component_duration = component->parent.duration;
1546       else
1547         pad->current_component_duration = -1;
1548
1549       if (track->edit_rate.n != source_track->edit_rate.n ||
1550           track->edit_rate.d != source_track->edit_rate.d) {
1551         pad->current_component_start +=
1552             gst_util_uint64_scale (component->start_position,
1553             source_track->edit_rate.n * track->edit_rate.d,
1554             source_track->edit_rate.d * track->edit_rate.n);
1555
1556         if (pad->current_component_duration != -1)
1557           pad->current_component_duration =
1558               gst_util_uint64_scale (pad->current_component_duration,
1559               source_track->edit_rate.n * track->edit_rate.d,
1560               source_track->edit_rate.d * track->edit_rate.n);
1561       } else {
1562         pad->current_component_start += component->start_position;
1563       }
1564       pad->current_essence_track_position = pad->current_component_start;
1565     }
1566
1567     /* NULL iff playing a source package */
1568     pad->current_component = component;
1569
1570     pad->current_essence_track = etrack;
1571
1572     if (etrack->tags) {
1573       if (pad->tags)
1574         gst_tag_list_insert (pad->tags, etrack->tags, GST_TAG_MERGE_REPLACE);
1575       else
1576         pad->tags = gst_tag_list_copy (etrack->tags);
1577     }
1578
1579     pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1580     if (pad_caps && !gst_caps_is_equal (pad_caps, etrack->caps)) {
1581       gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1582     } else if (!pad_caps) {
1583       GstEvent *event;
1584       gchar *stream_id;
1585
1586       gst_pad_set_event_function (GST_PAD_CAST (pad),
1587           GST_DEBUG_FUNCPTR (gst_mxf_demux_src_event));
1588
1589       gst_pad_set_query_function (GST_PAD_CAST (pad),
1590           GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query));
1591
1592       gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
1593       gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
1594
1595       stream_id =
1596           gst_pad_create_stream_id_printf (GST_PAD_CAST (pad),
1597           GST_ELEMENT_CAST (demux), "%03u", pad->track_id);
1598
1599       event =
1600           gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
1601       if (event) {
1602         if (gst_event_parse_group_id (event, &demux->group_id))
1603           demux->have_group_id = TRUE;
1604         else
1605           demux->have_group_id = FALSE;
1606         gst_event_unref (event);
1607       } else if (!demux->have_group_id) {
1608         demux->have_group_id = TRUE;
1609         demux->group_id = gst_util_group_id_next ();
1610       }
1611       event = gst_event_new_stream_start (stream_id);
1612       if (demux->have_group_id)
1613         gst_event_set_group_id (event, demux->group_id);
1614
1615       gst_pad_push_event (GST_PAD_CAST (pad), event);
1616       g_free (stream_id);
1617
1618       gst_pad_set_caps (GST_PAD_CAST (pad), etrack->caps);
1619
1620       pads = g_list_prepend (pads, gst_object_ref (pad));
1621
1622       g_ptr_array_add (demux->src, pad);
1623       pad->discont = TRUE;
1624     }
1625     if (pad_caps)
1626       gst_caps_unref (pad_caps);
1627   }
1628
1629   if (demux->src->len > 0) {
1630     for (i = 0; i < demux->src->len; i++) {
1631       GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
1632
1633       if (!pad->material_track || !pad->material_package) {
1634         GST_ERROR_OBJECT (demux, "Unable to update existing pad");
1635         ret = GST_FLOW_ERROR;
1636         goto error;
1637       }
1638     }
1639   } else {
1640     GST_ERROR_OBJECT (demux, "Couldn't create any streams");
1641     ret = GST_FLOW_ERROR;
1642     goto error;
1643   }
1644
1645   g_rw_lock_writer_unlock (&demux->metadata_lock);
1646
1647   for (l = pads; l; l = l->next) {
1648     gst_flow_combiner_add_pad (demux->flowcombiner, l->data);
1649     gst_element_add_pad (GST_ELEMENT_CAST (demux), l->data);
1650   }
1651   g_list_free (pads);
1652
1653   if (first_run)
1654     gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1655
1656   /* Re-check all existing partitions for source package linking in case the
1657    * header partition contains data (allowed in early MXF versions) */
1658   for (l = demux->partitions; l; l = l->next)
1659     gst_mxf_demux_partition_postcheck (demux, (GstMXFDemuxPartition *) l->data);
1660
1661   return GST_FLOW_OK;
1662
1663 error:
1664   g_rw_lock_writer_unlock (&demux->metadata_lock);
1665   return ret;
1666 }
1667
1668 static GstFlowReturn
1669 gst_mxf_demux_handle_metadata (GstMXFDemux * demux, GstMXFKLV * klv)
1670 {
1671   guint16 type;
1672   MXFMetadata *metadata = NULL, *old = NULL;
1673   GstMapInfo map;
1674   GstFlowReturn ret = GST_FLOW_OK;
1675
1676   type = GST_READ_UINT16_BE (&klv->key.u[13]);
1677
1678   GST_DEBUG_OBJECT (demux,
1679       "Handling metadata of size %" G_GSIZE_FORMAT " at offset %"
1680       G_GUINT64_FORMAT " of type 0x%04x", klv->length, klv->offset, type);
1681
1682   if (G_UNLIKELY (!demux->current_partition)) {
1683     GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1684     return GST_FLOW_ERROR;
1685   }
1686
1687   if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1688     GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1689     return GST_FLOW_ERROR;
1690   }
1691
1692   if (demux->current_partition->parsed_metadata) {
1693     GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1694     return GST_FLOW_OK;
1695   }
1696
1697   if (klv->length == 0)
1698     return GST_FLOW_OK;
1699   ret = gst_mxf_demux_fill_klv (demux, klv);
1700   if (ret != GST_FLOW_OK)
1701     return ret;
1702
1703   gst_buffer_map (klv->data, &map, GST_MAP_READ);
1704   metadata =
1705       mxf_metadata_new (type, &demux->current_partition->primer, demux->offset,
1706       map.data, map.size);
1707   gst_buffer_unmap (klv->data, &map);
1708
1709   if (!metadata) {
1710     GST_WARNING_OBJECT (demux,
1711         "Unknown or unhandled metadata of type 0x%04x", type);
1712     return GST_FLOW_OK;
1713   }
1714
1715   old =
1716       g_hash_table_lookup (demux->metadata,
1717       &MXF_METADATA_BASE (metadata)->instance_uid);
1718
1719   if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (metadata)) {
1720 #ifndef GST_DISABLE_GST_DEBUG
1721     gchar str[48];
1722 #endif
1723
1724     GST_DEBUG_OBJECT (demux,
1725         "Metadata with instance uid %s already exists and has different type '%s',"
1726         " expected '%s'",
1727         mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str),
1728         g_type_name (G_TYPE_FROM_INSTANCE (old)),
1729         g_type_name (G_TYPE_FROM_INSTANCE (metadata)));
1730     g_object_unref (metadata);
1731     return GST_FLOW_ERROR;
1732   } else if (old
1733       && MXF_METADATA_BASE (old)->offset >=
1734       MXF_METADATA_BASE (metadata)->offset) {
1735 #ifndef GST_DISABLE_GST_DEBUG
1736     gchar str[48];
1737 #endif
1738
1739     GST_DEBUG_OBJECT (demux,
1740         "Metadata with instance uid %s already exists and is newer",
1741         mxf_uuid_to_string (&MXF_METADATA_BASE (metadata)->instance_uid, str));
1742     g_object_unref (metadata);
1743     return GST_FLOW_OK;
1744   }
1745
1746   g_rw_lock_writer_lock (&demux->metadata_lock);
1747   demux->update_metadata = TRUE;
1748
1749   if (MXF_IS_METADATA_PREFACE (metadata)) {
1750     demux->preface = MXF_METADATA_PREFACE (metadata);
1751   }
1752
1753   gst_mxf_demux_reset_linked_metadata (demux);
1754
1755   g_hash_table_replace (demux->metadata,
1756       &MXF_METADATA_BASE (metadata)->instance_uid, metadata);
1757   g_rw_lock_writer_unlock (&demux->metadata_lock);
1758
1759   return ret;
1760 }
1761
1762 static GstFlowReturn
1763 gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux, GstMXFKLV * klv)
1764 {
1765   guint32 type;
1766   guint8 scheme;
1767   GstMapInfo map;
1768   GstFlowReturn ret = GST_FLOW_OK;
1769   MXFDescriptiveMetadata *m = NULL, *old = NULL;
1770
1771   scheme = GST_READ_UINT8 (&klv->key.u[12]);
1772   type = GST_READ_UINT24_BE (&klv->key.u[13]);
1773
1774   GST_DEBUG_OBJECT (demux,
1775       "Handling descriptive metadata of size %" G_GSIZE_FORMAT " at offset %"
1776       G_GUINT64_FORMAT " with scheme 0x%02x and type 0x%06x",
1777       klv->length, klv->offset, scheme, type);
1778
1779   if (G_UNLIKELY (!demux->current_partition)) {
1780     GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
1781     return GST_FLOW_ERROR;
1782   }
1783
1784   if (G_UNLIKELY (!demux->current_partition->primer.mappings)) {
1785     GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
1786     return GST_FLOW_ERROR;
1787   }
1788
1789   if (demux->current_partition->parsed_metadata) {
1790     GST_DEBUG_OBJECT (demux, "Metadata of this partition was already parsed");
1791     return GST_FLOW_OK;
1792   }
1793
1794   ret = gst_mxf_demux_fill_klv (demux, klv);
1795   if (ret != GST_FLOW_OK)
1796     return ret;
1797
1798   gst_buffer_map (klv->data, &map, GST_MAP_READ);
1799   m = mxf_descriptive_metadata_new (scheme, type,
1800       &demux->current_partition->primer, demux->offset, map.data, map.size);
1801   gst_buffer_unmap (klv->data, &map);
1802
1803   if (!m) {
1804     GST_WARNING_OBJECT (demux,
1805         "Unknown or unhandled descriptive metadata of scheme 0x%02x and type 0x%06x",
1806         scheme, type);
1807     return GST_FLOW_OK;
1808   }
1809
1810   old =
1811       g_hash_table_lookup (demux->metadata,
1812       &MXF_METADATA_BASE (m)->instance_uid);
1813
1814   if (old && G_TYPE_FROM_INSTANCE (old) != G_TYPE_FROM_INSTANCE (m)) {
1815 #ifndef GST_DISABLE_GST_DEBUG
1816     gchar str[48];
1817 #endif
1818
1819     GST_DEBUG_OBJECT (demux,
1820         "Metadata with instance uid %s already exists and has different type '%s',"
1821         " expected '%s'",
1822         mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str),
1823         g_type_name (G_TYPE_FROM_INSTANCE (old)),
1824         g_type_name (G_TYPE_FROM_INSTANCE (m)));
1825     g_object_unref (m);
1826     return GST_FLOW_ERROR;
1827   } else if (old
1828       && MXF_METADATA_BASE (old)->offset >= MXF_METADATA_BASE (m)->offset) {
1829 #ifndef GST_DISABLE_GST_DEBUG
1830     gchar str[48];
1831 #endif
1832
1833     GST_DEBUG_OBJECT (demux,
1834         "Metadata with instance uid %s already exists and is newer",
1835         mxf_uuid_to_string (&MXF_METADATA_BASE (m)->instance_uid, str));
1836     g_object_unref (m);
1837     return GST_FLOW_OK;
1838   }
1839
1840   g_rw_lock_writer_lock (&demux->metadata_lock);
1841
1842   demux->update_metadata = TRUE;
1843   gst_mxf_demux_reset_linked_metadata (demux);
1844
1845   g_hash_table_replace (demux->metadata, &MXF_METADATA_BASE (m)->instance_uid,
1846       m);
1847
1848   g_rw_lock_writer_unlock (&demux->metadata_lock);
1849
1850   return ret;
1851 }
1852
1853 static GstFlowReturn
1854 gst_mxf_demux_handle_generic_container_system_item (GstMXFDemux * demux,
1855     GstMXFKLV * klv)
1856 {
1857   GST_DEBUG_OBJECT (demux,
1858       "Handling generic container system item of size %" G_GSIZE_FORMAT
1859       " at offset %" G_GUINT64_FORMAT, klv->length, klv->offset);
1860
1861   if (demux->current_partition->essence_container_offset == 0)
1862     demux->current_partition->essence_container_offset =
1863         demux->offset - demux->current_partition->partition.this_partition -
1864         demux->run_in;
1865
1866   /* TODO: parse this */
1867   return GST_FLOW_OK;
1868 }
1869
1870 static GstFlowReturn
1871 gst_mxf_demux_pad_set_component (GstMXFDemux * demux, GstMXFDemuxPad * pad,
1872     guint i)
1873 {
1874   GstFlowReturn ret = GST_FLOW_OK;
1875   GstCaps *pad_caps;
1876   MXFMetadataSequence *sequence;
1877   guint k;
1878   MXFMetadataSourcePackage *source_package = NULL;
1879   MXFMetadataTimelineTrack *source_track = NULL;
1880   gboolean update = (pad->current_component_index != i);
1881
1882   pad->current_component_index = i;
1883
1884   sequence = pad->material_track->parent.sequence;
1885
1886   if (pad->current_component_index >= sequence->n_structural_components) {
1887     GST_DEBUG_OBJECT (demux, "After last structural component");
1888     pad->current_component_index = sequence->n_structural_components - 1;
1889     ret = GST_FLOW_EOS;
1890   }
1891
1892   GST_DEBUG_OBJECT (demux, "Switching to component %u",
1893       pad->current_component_index);
1894
1895   pad->current_component =
1896       MXF_METADATA_SOURCE_CLIP (sequence->structural_components[pad->
1897           current_component_index]);
1898   if (pad->current_component == NULL) {
1899     GST_ERROR_OBJECT (demux, "No such structural component");
1900     return GST_FLOW_ERROR;
1901   }
1902
1903   if (!pad->current_component->source_package
1904       || !pad->current_component->source_package->top_level
1905       || !MXF_METADATA_GENERIC_PACKAGE (pad->current_component->
1906           source_package)->tracks) {
1907     GST_ERROR_OBJECT (demux, "Invalid component");
1908     return GST_FLOW_ERROR;
1909   }
1910
1911   source_package = pad->current_component->source_package;
1912
1913   for (k = 0; k < source_package->parent.n_tracks; k++) {
1914     MXFMetadataTrack *tmp = source_package->parent.tracks[k];
1915
1916     if (tmp->track_id == pad->current_component->source_track_id) {
1917       source_track = MXF_METADATA_TIMELINE_TRACK (tmp);
1918       break;
1919     }
1920   }
1921
1922   if (!source_track) {
1923     GST_ERROR_OBJECT (demux, "No source track found");
1924     return GST_FLOW_ERROR;
1925   }
1926
1927   pad->current_essence_track = NULL;
1928
1929   for (k = 0; k < demux->essence_tracks->len; k++) {
1930     GstMXFDemuxEssenceTrack *tmp =
1931         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, k);
1932
1933     if (tmp->source_package == source_package &&
1934         tmp->source_track == source_track) {
1935       pad->current_essence_track = tmp;
1936       break;
1937     }
1938   }
1939
1940   if (!pad->current_essence_track) {
1941     GST_ERROR_OBJECT (demux, "No corresponding essence track found");
1942     return GST_FLOW_ERROR;
1943   }
1944
1945   if (!source_package->descriptor) {
1946     GST_ERROR_OBJECT (demux, "Source package has no descriptors");
1947     return GST_FLOW_ERROR;
1948   }
1949
1950   if (!source_track->parent.descriptor) {
1951     GST_ERROR_OBJECT (demux, "No descriptor found for track");
1952     return GST_FLOW_ERROR;
1953   }
1954
1955   if (source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
1956     GST_ERROR_OBJECT (demux, "Source track has invalid edit rate");
1957     return GST_FLOW_ERROR;
1958   }
1959
1960   pad->current_component_start_position = 0;
1961   for (k = 0; k < i; k++) {
1962     pad->current_component_start_position +=
1963         MXF_METADATA_SOURCE_CLIP (sequence->structural_components[k])->
1964         parent.duration;
1965   }
1966
1967   if (pad->current_component->parent.duration >= -1)
1968     pad->current_component_duration = pad->current_component->parent.duration;
1969   else
1970     pad->current_component_duration = -1;
1971
1972   if (pad->material_track->edit_rate.n != source_track->edit_rate.n ||
1973       pad->material_track->edit_rate.d != source_track->edit_rate.d) {
1974     pad->current_component_start +=
1975         gst_util_uint64_scale (pad->current_component->start_position,
1976         source_track->edit_rate.n * pad->material_track->edit_rate.d,
1977         source_track->edit_rate.d * pad->material_track->edit_rate.n);
1978
1979     if (pad->current_component_duration != -1)
1980       pad->current_component_duration =
1981           gst_util_uint64_scale (pad->current_component_duration,
1982           source_track->edit_rate.n * pad->material_track->edit_rate.d,
1983           source_track->edit_rate.d * pad->material_track->edit_rate.n);
1984   } else {
1985     pad->current_component_start += pad->current_component->start_position;
1986   }
1987   pad->current_essence_track_position = pad->current_component_start;
1988
1989   pad_caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
1990   if (!pad_caps
1991       || !gst_caps_is_equal (pad_caps, pad->current_essence_track->caps)) {
1992     gst_pad_set_caps (GST_PAD_CAST (pad), pad->current_essence_track->caps);
1993   }
1994   if (pad_caps)
1995     gst_caps_unref (pad_caps);
1996
1997   if (update) {
1998     if (pad->tags) {
1999       if (pad->current_essence_track->tags)
2000         gst_tag_list_insert (pad->tags, pad->current_essence_track->tags,
2001             GST_TAG_MERGE_REPLACE);
2002     } else {
2003       if (pad->current_essence_track->tags)
2004         pad->tags = gst_tag_list_copy (pad->current_essence_track->tags);
2005     }
2006   }
2007
2008   if (ret == GST_FLOW_EOS) {
2009     pad->current_essence_track_position += pad->current_component_duration;
2010   }
2011
2012   return ret;
2013 }
2014
2015 /*
2016  * Find the partition containing the stream offset of the given track
2017  * */
2018 static GstMXFDemuxPartition *
2019 get_partition_for_stream_offset (GstMXFDemux * demux,
2020     GstMXFDemuxEssenceTrack * etrack, guint64 stream_offset)
2021 {
2022   GList *tmp;
2023   GstMXFDemuxPartition *offset_partition = NULL, *next_partition = NULL;
2024
2025   for (tmp = demux->partitions; tmp; tmp = tmp->next) {
2026     GstMXFDemuxPartition *partition = tmp->data;
2027
2028     if (!next_partition && offset_partition)
2029       next_partition = partition;
2030
2031     if (partition->partition.body_sid != etrack->body_sid)
2032       continue;
2033     if (partition->partition.body_offset > stream_offset)
2034       break;
2035
2036     offset_partition = partition;
2037     next_partition = NULL;
2038   }
2039
2040   if (offset_partition
2041       && stream_offset < offset_partition->partition.body_offset)
2042     return NULL;
2043
2044   GST_DEBUG_OBJECT (demux,
2045       "Found this_partition:%" G_GUINT64_FORMAT " body_offset:%"
2046       G_GUINT64_FORMAT, offset_partition->partition.this_partition,
2047       offset_partition->partition.body_offset);
2048
2049   /* Are we overriding into the next partition ? */
2050   if (next_partition) {
2051     guint64 partition_essence_size =
2052         next_partition->partition.this_partition -
2053         offset_partition->partition.this_partition +
2054         offset_partition->essence_container_offset;
2055     guint64 in_partition =
2056         stream_offset - offset_partition->partition.body_offset;
2057     GST_DEBUG_OBJECT (demux,
2058         "Followed by this_partition:%" G_GUINT64_FORMAT " body_offset:%"
2059         G_GUINT64_FORMAT, next_partition->partition.this_partition,
2060         next_partition->partition.body_offset);
2061
2062     if (in_partition >= partition_essence_size) {
2063       GST_WARNING_OBJECT (demux,
2064           "stream_offset %" G_GUINT64_FORMAT
2065           " in track body_sid:% index_sid:%d leaks into next unrelated partition (body_sid:%d / index_sid:%d)",
2066           stream_offset, etrack->body_sid, etrack->index_sid,
2067           next_partition->partition.body_sid,
2068           next_partition->partition.index_sid);
2069       return NULL;
2070     }
2071   }
2072   return offset_partition;
2073 }
2074
2075 static GstMXFDemuxIndexTable *
2076 get_track_index_table (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack)
2077 {
2078   GList *l;
2079
2080   /* Look in the indextables */
2081   for (l = demux->index_tables; l; l = l->next) {
2082     GstMXFDemuxIndexTable *tmp = l->data;
2083
2084     if (tmp->body_sid == etrack->body_sid
2085         && tmp->index_sid == etrack->index_sid) {
2086       return tmp;
2087     }
2088   }
2089
2090   return NULL;
2091 }
2092
2093 static guint32
2094 get_track_max_temporal_offset (GstMXFDemux * demux,
2095     GstMXFDemuxEssenceTrack * etrack)
2096 {
2097   GstMXFDemuxIndexTable *table;
2098
2099   if (etrack->intra_only)
2100     return 0;
2101
2102   table = get_track_index_table (demux, etrack);
2103
2104   if (table)
2105     return table->max_temporal_offset;
2106   return 0;
2107 }
2108
2109 static guint64
2110 find_offset (GArray * offsets, gint64 * position, gboolean keyframe)
2111 {
2112   GstMXFDemuxIndex *idx;
2113   guint64 current_offset = -1;
2114   gint64 current_position = *position;
2115
2116   if (!offsets || offsets->len <= *position)
2117     return -1;
2118
2119   idx = &g_array_index (offsets, GstMXFDemuxIndex, *position);
2120   if (idx->offset != 0 && (!keyframe || idx->keyframe)) {
2121     current_offset = idx->offset;
2122   } else if (idx->offset != 0) {
2123     current_position--;
2124     while (current_position >= 0) {
2125       GST_LOG ("current_position %" G_GINT64_FORMAT, current_position);
2126       idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
2127       if (idx->offset == 0) {
2128         GST_LOG ("breaking offset 0");
2129         break;
2130       } else if (!idx->keyframe) {
2131         current_position--;
2132         continue;
2133       } else {
2134         GST_LOG ("Breaking found offset");
2135         current_offset = idx->offset;
2136         break;
2137       }
2138     }
2139   }
2140
2141   if (current_offset == -1)
2142     return -1;
2143
2144   *position = current_position;
2145   return current_offset;
2146 }
2147
2148 /**
2149  * find_edit_entry:
2150  * @demux: The demuxer
2151  * @etrack: The target essence track
2152  * @position: An edit unit position
2153  * @keyframe: if TRUE search for supporting keyframe
2154  * @entry: (out): Will be filled with the matching entry information
2155  *
2156  * Finds the edit entry of @etrack for the given edit unit @position and fill
2157  * @entry with the information about that edit entry. If @keyframe is TRUE, the
2158  * supporting entry (i.e. keyframe) for the given position will be searched for.
2159  *
2160  * For frame-wrapped contents, the returned offset will be the position of the
2161  * KLV of the content. For clip-wrapped content, the returned offset will be the
2162  * position of the essence (i.e. without KLV header) and the entry will specify
2163  * the size (in bytes).
2164  *
2165  * The returned entry will also specify the duration (in edit units) of the
2166  * content, which can be different from 1 for special cases (such as raw audio
2167  * where multiple samples could be aggregated).
2168  *
2169  * Returns: TRUE if the entry was found and @entry was properly filled, else
2170  * FALSE.
2171  */
2172 static gboolean
2173 find_edit_entry (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack,
2174     gint64 position, gboolean keyframe, GstMXFDemuxIndex * entry)
2175 {
2176   GstMXFDemuxIndexTable *index_table = NULL;
2177   guint i;
2178   MXFIndexTableSegment *segment = NULL;
2179   GstMXFDemuxPartition *offset_partition = NULL;
2180   guint64 stream_offset = G_MAXUINT64, absolute_offset;
2181
2182   GST_DEBUG_OBJECT (demux,
2183       "track %d body_sid:%d index_sid:%d delta_id:%d position:%" G_GINT64_FORMAT
2184       " keyframe:%d", etrack->track_id, etrack->body_sid,
2185       etrack->index_sid, etrack->delta_id, position, keyframe);
2186
2187   /* Default values */
2188   entry->duration = 1;
2189   /* By default every entry is a keyframe unless specified otherwise */
2190   entry->keyframe = TRUE;
2191
2192   /* Look in the track offsets */
2193   if (etrack->offsets && etrack->offsets->len > position) {
2194     if (find_offset (etrack->offsets, &position, keyframe) != -1) {
2195       *entry = g_array_index (etrack->offsets, GstMXFDemuxIndex, position);
2196       GST_LOG_OBJECT (demux, "Found entry in track offsets");
2197       return TRUE;
2198     } else
2199       GST_LOG_OBJECT (demux, "Didn't find entry in track offsets");
2200   }
2201
2202   /* Look in the indextables */
2203   index_table = get_track_index_table (demux, etrack);
2204
2205   if (!index_table) {
2206     GST_DEBUG_OBJECT (demux,
2207         "Couldn't find index table for body_sid:%d index_sid:%d",
2208         etrack->body_sid, etrack->index_sid);
2209     return FALSE;
2210   }
2211
2212   GST_DEBUG_OBJECT (demux,
2213       "Looking for position %" G_GINT64_FORMAT
2214       " in index table (max temporal offset %u)",
2215       etrack->position, index_table->max_temporal_offset);
2216
2217   /* Searching for a position in index tables works in 3 steps:
2218    *
2219    * 1. Figure out the table segment containing that position
2220    * 2. Figure out the "stream offset" (and additional flags/timing) of that
2221    *    position from the table segment.
2222    * 3. Figure out the "absolute offset" of that "stream offset" using partitions
2223    */
2224
2225 search_in_segment:
2226
2227   /* Find matching index segment */
2228   GST_DEBUG_OBJECT (demux, "Look for entry in %d segments",
2229       index_table->segments->len);
2230   for (i = 0; i < index_table->segments->len; i++) {
2231     MXFIndexTableSegment *cand =
2232         &g_array_index (index_table->segments, MXFIndexTableSegment, i);
2233     if (position >= cand->index_start_position && (cand->index_duration == 0
2234             || position <
2235             (cand->index_start_position + cand->index_duration))) {
2236       GST_DEBUG_OBJECT (demux,
2237           "Entry is in Segment #%d , start: %" G_GINT64_FORMAT " , duration: %"
2238           G_GINT64_FORMAT, i, cand->index_start_position, cand->index_duration);
2239       segment = cand;
2240       break;
2241     }
2242   }
2243   if (!segment) {
2244     GST_DEBUG_OBJECT (demux,
2245         "Didn't find index table segment for position %" G_GINT64_FORMAT,
2246         position);
2247     return FALSE;
2248   }
2249
2250   /* Were we asked for a keyframe ? */
2251   if (keyframe) {
2252     if (segment->edit_unit_byte_count && !segment->n_index_entries) {
2253       GST_LOG_OBJECT (demux,
2254           "Index table without entries, directly using requested position for keyframe search");
2255     } else {
2256       gint64 candidate;
2257       GST_LOG_OBJECT (demux, "keyframe search");
2258       /* Search backwards for keyframe */
2259       for (candidate = position; candidate >= segment->index_start_position;
2260           candidate--) {
2261         MXFIndexEntry *segment_index_entry =
2262             &segment->index_entries[candidate - segment->index_start_position];
2263
2264         /* Match */
2265         if (segment_index_entry->flags & 0x80) {
2266           GST_LOG_OBJECT (demux, "Found keyframe at position %" G_GINT64_FORMAT,
2267               candidate);
2268           position = candidate;
2269           break;
2270         }
2271
2272         /* If a keyframe offset is specified and valid, use that */
2273         if (segment_index_entry->key_frame_offset
2274             && !(segment_index_entry->flags & 0x08)) {
2275           GST_DEBUG_OBJECT (demux, "Using keyframe offset %d",
2276               segment_index_entry->key_frame_offset);
2277           position = candidate + segment_index_entry->key_frame_offset;
2278           if (position < segment->index_start_position) {
2279             GST_DEBUG_OBJECT (demux, "keyframe info is in previous segment");
2280             goto search_in_segment;
2281           }
2282           break;
2283         }
2284
2285         /* If we reached the beginning, use that */
2286         if (candidate == 0) {
2287           GST_LOG_OBJECT (demux,
2288               "Reached position 0 while searching for keyframe");
2289           position = 0;
2290           break;
2291         }
2292
2293         /* If we looped past the beginning of this segment, go to the previous one */
2294         if (candidate == segment->index_start_position) {
2295           position = candidate - 1;
2296           GST_LOG_OBJECT (demux, "Looping with new position %" G_GINT64_FORMAT,
2297               position);
2298           goto search_in_segment;
2299         }
2300
2301         /* loop back to check previous entry */
2302       }
2303     }
2304   }
2305
2306   /* Figure out the stream offset (also called "body offset" in specification) */
2307   if (segment->edit_unit_byte_count && !segment->n_index_entries) {
2308     /* Constant entry table. */
2309     stream_offset = position * segment->edit_unit_byte_count;
2310     if (etrack->delta_id >= 0) {
2311       MXFDeltaEntry *delta_entry = &segment->delta_entries[etrack->delta_id];
2312       GST_LOG_OBJECT (demux,
2313           "Using delta %d pos_table_index:%d slice:%u element_delta:%u",
2314           etrack->delta_id, delta_entry->pos_table_index, delta_entry->slice,
2315           delta_entry->element_delta);
2316       stream_offset += delta_entry->element_delta;
2317     } else if (etrack->min_edit_units != 1) {
2318       GST_LOG_OBJECT (demux, "Handling minimum edit unit %u",
2319           etrack->min_edit_units);
2320       entry->duration =
2321           MIN (etrack->min_edit_units,
2322           (segment->index_start_position + segment->index_duration) - position);
2323       entry->size = segment->edit_unit_byte_count * entry->duration;
2324     } else {
2325       entry->size = segment->edit_unit_byte_count;
2326     }
2327   } else if (segment->n_index_entries) {
2328     MXFIndexEntry *segment_index_entry;
2329     MXFDeltaEntry *delta_entry = NULL;
2330     g_assert (position <=
2331         segment->index_start_position + segment->n_index_entries);
2332     segment_index_entry =
2333         &segment->index_entries[position - segment->index_start_position];
2334     stream_offset = segment_index_entry->stream_offset;
2335
2336     if (segment->n_delta_entries > 0)
2337       delta_entry = &segment->delta_entries[etrack->delta_id];
2338
2339     if (delta_entry) {
2340       GST_LOG_OBJECT (demux,
2341           "Using delta %d pos_table_index:%d slice:%u element_delta:%u",
2342           etrack->delta_id, delta_entry->pos_table_index, delta_entry->slice,
2343           delta_entry->element_delta);
2344
2345       /* Apply offset from slice/delta if needed */
2346       if (delta_entry->slice)
2347         stream_offset +=
2348             segment_index_entry->slice_offset[delta_entry->slice - 1];
2349       stream_offset += delta_entry->element_delta;
2350       if (delta_entry->pos_table_index == -1) {
2351         entry->keyframe = (segment_index_entry->flags & 0x80) == 0x80;
2352       }
2353       /* FIXME : Handle fractional offset position (delta_entry->pos_table_offset > 0) */
2354     }
2355
2356     /* Apply reverse temporal reordering if present */
2357     if (index_table->reordered_delta_entry == etrack->delta_id) {
2358       if (position >= index_table->reverse_temporal_offsets->len) {
2359         GST_WARNING_OBJECT (demux,
2360             "Can't apply temporal offset for position %" G_GINT64_FORMAT
2361             " (max:%d)", position, index_table->reverse_temporal_offsets->len);
2362       }
2363       if (demux->temporal_order_misuse) {
2364         GST_DEBUG_OBJECT (demux, "Handling temporal order misuse");
2365         entry->pts = position + segment_index_entry->temporal_offset;
2366       } else {
2367         entry->pts =
2368             position + g_array_index (index_table->reverse_temporal_offsets,
2369             gint8, position);
2370         GST_LOG_OBJECT (demux,
2371             "Applied temporal offset. dts:%" G_GINT64_FORMAT " pts:%"
2372             G_GINT64_FORMAT, position, entry->pts);
2373       }
2374     } else
2375       entry->pts = position;
2376   } else {
2377     /* Note : This should have been handled in the parser */
2378     GST_WARNING_OBJECT (demux,
2379         "Can't handle index tables without entries nor constant edit unit byte count");
2380     return FALSE;
2381   }
2382
2383   /* Find the partition containing the stream offset for this track */
2384   offset_partition =
2385       get_partition_for_stream_offset (demux, etrack, stream_offset);
2386
2387   if (!offset_partition) {
2388     GST_WARNING_OBJECT (demux,
2389         "Couldn't find matching partition for stream offset %" G_GUINT64_FORMAT,
2390         stream_offset);
2391     return FALSE;
2392   } else {
2393     GST_DEBUG_OBJECT (demux, "Entry is in partition %" G_GUINT64_FORMAT,
2394         offset_partition->partition.this_partition);
2395   }
2396
2397   /* Convert stream offset to absolute offset using matching partition */
2398   absolute_offset =
2399       offset_partition->partition.this_partition +
2400       offset_partition->essence_container_offset + (stream_offset -
2401       offset_partition->partition.body_offset);
2402
2403   GST_LOG_OBJECT (demux,
2404       "track %d position:%" G_GINT64_FORMAT " stream_offset %" G_GUINT64_FORMAT
2405       " matches to absolute offset %" G_GUINT64_FORMAT, etrack->track_id,
2406       position, stream_offset, absolute_offset);
2407   entry->initialized = TRUE;
2408   entry->offset = absolute_offset;
2409   entry->dts = position;
2410
2411   return TRUE;
2412 }
2413
2414 /**
2415  * find_entry_for_offset:
2416  * @demux: The demuxer
2417  * @etrack: The target essence track
2418  * @offset: An absolute byte offset (excluding run_in)
2419  * @entry: (out): Will be filled with the matching entry information
2420  *
2421  * Find the entry located at the given absolute byte offset.
2422  *
2423  * Note: the offset requested should be in the current partition !
2424  *
2425  * Returns: TRUE if the entry was found and @entry was properly filled, else
2426  * FALSE.
2427  */
2428 static gboolean
2429 find_entry_for_offset (GstMXFDemux * demux, GstMXFDemuxEssenceTrack * etrack,
2430     guint64 offset, GstMXFDemuxIndex * retentry)
2431 {
2432   GstMXFDemuxIndexTable *index_table = get_track_index_table (demux, etrack);
2433   guint i;
2434   MXFIndexTableSegment *index_segment = NULL;
2435   GstMXFDemuxPartition *partition = demux->current_partition;
2436   guint64 original_offset = offset;
2437   guint64 cp_offset = 0;        /* Offset in Content Package */
2438   MXFIndexEntry *index_entry = NULL;
2439   MXFDeltaEntry *delta_entry = NULL;
2440   gint64 position = 0;
2441
2442   GST_DEBUG_OBJECT (demux,
2443       "track %d body_sid:%d index_sid:%d offset:%" G_GUINT64_FORMAT,
2444       etrack->track_id, etrack->body_sid, etrack->index_sid, offset);
2445
2446   /* Default value */
2447   retentry->duration = 1;
2448   retentry->keyframe = TRUE;
2449
2450   /* Index-less search */
2451   if (etrack->offsets) {
2452     for (i = 0; i < etrack->offsets->len; i++) {
2453       GstMXFDemuxIndex *idx =
2454           &g_array_index (etrack->offsets, GstMXFDemuxIndex, i);
2455
2456       if (idx->initialized && idx->offset != 0 && idx->offset == offset) {
2457         *retentry = *idx;
2458         GST_DEBUG_OBJECT (demux,
2459             "Found in track index. Position:%" G_GINT64_FORMAT, idx->dts);
2460         return TRUE;
2461       }
2462     }
2463   }
2464
2465   /* Actual index search */
2466   if (!index_table || !index_table->segments->len) {
2467     GST_WARNING_OBJECT (demux, "No index table or entries to search in");
2468     return FALSE;
2469   }
2470
2471   if (!partition) {
2472     GST_WARNING_OBJECT (demux, "No current partition for search");
2473     return FALSE;
2474   }
2475
2476   /* Searching for a stream position from an absolute offset works in 3 steps:
2477    *
2478    * 1. Convert the absolute offset to a "stream offset" based on the partition
2479    *    information.
2480    * 2. Find the segment for that "stream offset"
2481    * 3. Match the entry within that segment
2482    */
2483
2484   /* Convert to stream offset */
2485   GST_LOG_OBJECT (demux,
2486       "offset %" G_GUINT64_FORMAT " this_partition:%" G_GUINT64_FORMAT
2487       " essence_container_offset:%" G_GINT64_FORMAT " partition body offset %"
2488       G_GINT64_FORMAT, offset, partition->partition.this_partition,
2489       partition->essence_container_offset, partition->partition.body_offset);
2490   offset =
2491       offset - partition->partition.this_partition -
2492       partition->essence_container_offset + partition->partition.body_offset;
2493
2494   GST_LOG_OBJECT (demux, "stream offset %" G_GUINT64_FORMAT, offset);
2495
2496   /* Find the segment that covers the given stream offset (the highest one that
2497    * covers that offset) */
2498   for (i = index_table->segments->len - 1; i >= 0; i--) {
2499     index_segment =
2500         &g_array_index (index_table->segments, MXFIndexTableSegment, i);
2501     GST_DEBUG_OBJECT (demux,
2502         "Checking segment #%d (essence_offset %" G_GUINT64_FORMAT ")", i,
2503         index_segment->segment_start_offset);
2504     /* Not in the right segment yet */
2505     if (offset >= index_segment->segment_start_offset) {
2506       GST_LOG_OBJECT (demux, "Found");
2507       break;
2508     }
2509   }
2510   if (!index_segment) {
2511     GST_WARNING_OBJECT (demux,
2512         "Couldn't find index table segment for given offset");
2513     return FALSE;
2514   }
2515
2516   /* In the right segment, figure out:
2517    * * the offset in the content package,
2518    * * the position in edit units
2519    * * the matching entry (if the table has entries)
2520    */
2521   if (index_segment->edit_unit_byte_count) {
2522     cp_offset = offset % index_segment->edit_unit_byte_count;
2523     position = offset / index_segment->edit_unit_byte_count;
2524     /* Boundary check */
2525     if ((position < index_segment->index_start_position)
2526         || (index_segment->index_duration
2527             && position >
2528             (index_segment->index_start_position +
2529                 index_segment->index_duration))) {
2530       GST_WARNING_OBJECT (demux,
2531           "Invalid offset, exceeds table segment limits");
2532       return FALSE;
2533     }
2534     if (etrack->min_edit_units != 1) {
2535       retentry->duration = MIN (etrack->min_edit_units,
2536           (index_segment->index_start_position +
2537               index_segment->index_duration) - position);
2538       retentry->size = index_segment->edit_unit_byte_count * retentry->duration;
2539     } else {
2540       retentry->size = index_segment->edit_unit_byte_count;
2541     }
2542   } else {
2543     /* Find the content package entry containing this offset */
2544     guint cpidx;
2545     for (cpidx = 0; cpidx < index_segment->n_index_entries; cpidx++) {
2546       index_entry = &index_segment->index_entries[cpidx];
2547       GST_DEBUG_OBJECT (demux,
2548           "entry #%u offset:%" G_GUINT64_FORMAT " stream_offset:%"
2549           G_GUINT64_FORMAT, cpidx, offset, index_entry->stream_offset);
2550       if (index_entry->stream_offset == offset) {
2551         index_entry = &index_segment->index_entries[cpidx];
2552         /* exactly on the entry */
2553         cp_offset = offset - index_entry->stream_offset;
2554         position = index_segment->index_start_position + cpidx;
2555         break;
2556       }
2557       if (index_entry->stream_offset > offset && cpidx > 0) {
2558         index_entry = &index_segment->index_entries[cpidx - 1];
2559         /* One too far, result is in previous entry */
2560         cp_offset = offset - index_entry->stream_offset;
2561         position = index_segment->index_start_position + cpidx - 1;
2562         break;
2563       }
2564     }
2565     if (cpidx == index_segment->n_index_entries) {
2566       GST_WARNING_OBJECT (demux,
2567           "offset exceeds maximum number of entries in table segment");
2568       return FALSE;
2569     }
2570   }
2571
2572   /* If the track comes from an interleaved essence container and doesn't have a
2573    * delta_id set, figure it out now */
2574   if (G_UNLIKELY (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN)) {
2575     guint delta;
2576     GST_DEBUG_OBJECT (demux,
2577         "Unknown delta_id for track. Attempting to resolve it");
2578
2579     if (index_segment->n_delta_entries == 0) {
2580       /* No delta entries, nothing we can do about this */
2581       GST_DEBUG_OBJECT (demux, "Index table has no delta entries, ignoring");
2582       etrack->delta_id = MXF_INDEX_DELTA_ID_IGNORE;
2583     } else if (!index_entry) {
2584       for (delta = 0; delta < index_segment->n_delta_entries; delta++) {
2585         /* No entry, therefore no slices */
2586         GST_LOG_OBJECT (demux,
2587             "delta #%d offset %" G_GUINT64_FORMAT " cp_offs:%" G_GUINT64_FORMAT
2588             " element_delta:%u", delta, offset, cp_offset,
2589             index_segment->delta_entries[delta].element_delta);
2590         if (cp_offset == index_segment->delta_entries[delta].element_delta) {
2591           GST_DEBUG_OBJECT (demux, "Matched to delta %d", delta);
2592           etrack->delta_id = delta;
2593           delta_entry = &index_segment->delta_entries[delta];
2594           break;
2595         }
2596       }
2597     } else {
2598       for (delta = 0; delta < index_segment->n_delta_entries; delta++) {
2599         guint64 delta_offs = 0;
2600         /* If we are not in the first slice, take that offset into account */
2601         if (index_segment->delta_entries[delta].slice)
2602           delta_offs =
2603               index_entry->slice_offset[index_segment->
2604               delta_entries[delta].slice - 1];
2605         /* Add the offset for this delta */
2606         delta_offs += index_segment->delta_entries[delta].element_delta;
2607         if (cp_offset == delta_offs) {
2608           GST_DEBUG_OBJECT (demux, "Matched to delta %d", delta);
2609           etrack->delta_id = delta;
2610           delta_entry = &index_segment->delta_entries[delta];
2611           break;
2612         }
2613       }
2614
2615     }
2616     /* If we didn't managed to match, ignore it from now on */
2617     if (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN) {
2618       GST_WARNING_OBJECT (demux,
2619           "Couldn't match delta id, ignoring it from now on");
2620       etrack->delta_id = MXF_INDEX_DELTA_ID_IGNORE;
2621     }
2622   } else if (index_segment->n_delta_entries > 0) {
2623     delta_entry = &index_segment->delta_entries[etrack->delta_id];
2624   }
2625
2626   if (index_entry && delta_entry && delta_entry->pos_table_index == -1) {
2627     retentry->keyframe = (index_entry->flags & 0x80) == 0x80;
2628     if (!demux->temporal_order_misuse)
2629       retentry->pts =
2630           position + g_array_index (index_table->reverse_temporal_offsets,
2631           gint8, position);
2632     else
2633       retentry->pts = position + index_entry->temporal_offset;
2634     GST_LOG_OBJECT (demux,
2635         "Applied temporal offset. dts:%" G_GINT64_FORMAT " pts:%"
2636         G_GINT64_FORMAT, position, retentry->pts);
2637   } else
2638     retentry->pts = position;
2639
2640   /* FIXME : check if position and cp_offs matches the table */
2641   GST_LOG_OBJECT (demux, "Found in index table. position:%" G_GINT64_FORMAT,
2642       position);
2643   retentry->initialized = TRUE;
2644   retentry->offset = original_offset;
2645   retentry->dts = position;
2646
2647   return TRUE;
2648 }
2649
2650 static GstFlowReturn
2651 gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
2652     GstMXFKLV * klv, gboolean peek)
2653 {
2654   GstFlowReturn ret = GST_FLOW_OK;
2655   guint32 track_number;
2656   guint i;
2657   GstBuffer *inbuf = NULL;
2658   GstBuffer *outbuf = NULL;
2659   GstMXFDemuxEssenceTrack *etrack = NULL;
2660   /* As in GstMXFDemuxIndex */
2661   guint64 pts = G_MAXUINT64;
2662   gint32 max_temporal_offset = 0;
2663   GstMXFDemuxIndex index_entry = { 0, };
2664   guint64 offset;
2665
2666   GST_DEBUG_OBJECT (demux,
2667       "Handling generic container essence element of size %" G_GSIZE_FORMAT
2668       " at offset %" G_GUINT64_FORMAT, klv->length,
2669       klv->offset + klv->consumed);
2670
2671   GST_DEBUG_OBJECT (demux, "  type = 0x%02x", klv->key.u[12]);
2672   GST_DEBUG_OBJECT (demux, "  essence element count = 0x%02x", klv->key.u[13]);
2673   GST_DEBUG_OBJECT (demux, "  essence element type = 0x%02x", klv->key.u[14]);
2674   GST_DEBUG_OBJECT (demux, "  essence element number = 0x%02x", klv->key.u[15]);
2675
2676   if (demux->current_partition->essence_container_offset == 0) {
2677     demux->current_partition->essence_container_offset =
2678         demux->offset - demux->current_partition->partition.this_partition -
2679         demux->run_in;
2680     if (demux->current_partition->single_track
2681         && demux->current_partition->single_track->wrapping !=
2682         MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2683       demux->current_partition->essence_container_offset += klv->data_offset;
2684       demux->current_partition->clip_klv = *klv;
2685       /* "consume" the initial bytes of the KLV */
2686       klv->consumed = klv->data_offset;
2687       GST_DEBUG_OBJECT (demux,
2688           "Non-frame wrapping, updated essence_container_offset to %"
2689           G_GUINT64_FORMAT, demux->current_partition->essence_container_offset);
2690     }
2691   }
2692
2693   if (!demux->current_package) {
2694     GST_ERROR_OBJECT (demux, "No package selected yet");
2695     return GST_FLOW_ERROR;
2696   }
2697
2698   if (demux->src->len == 0) {
2699     GST_ERROR_OBJECT (demux, "No streams created yet");
2700     return GST_FLOW_ERROR;
2701   }
2702
2703   if (demux->essence_tracks->len == 0) {
2704     GST_ERROR_OBJECT (demux, "No essence streams found in the metadata");
2705     return GST_FLOW_ERROR;
2706   }
2707
2708   /* Identify and fetch the essence track */
2709   track_number = GST_READ_UINT32_BE (&klv->key.u[12]);
2710
2711   etrack = demux->current_partition->single_track;
2712   if (!etrack) {
2713     for (i = 0; i < demux->essence_tracks->len; i++) {
2714       GstMXFDemuxEssenceTrack *tmp =
2715           &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
2716
2717       if (tmp->body_sid == demux->current_partition->partition.body_sid &&
2718           (tmp->track_number == track_number || tmp->track_number == 0)) {
2719         etrack = tmp;
2720         break;
2721       }
2722     }
2723
2724     if (!etrack) {
2725       GST_DEBUG_OBJECT (demux,
2726           "No essence track for this essence element found");
2727       return GST_FLOW_OK;
2728     }
2729   }
2730
2731   GST_DEBUG_OBJECT (demux,
2732       "Handling generic container essence (track %d , position:%"
2733       G_GINT64_FORMAT ", number: 0x%08x , frame-wrapped:%d)", etrack->track_id,
2734       etrack->position, track_number,
2735       etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
2736
2737   /* Fetch the current entry.
2738    *
2739    * 1. If we don't have a current position, use find_entry_for_offset()
2740    * 2. If we do have a position, use find_edit_entry()
2741    *
2742    * 3. If we are dealing with frame-wrapped content, pull the corresponding
2743    *    data from upstream (because it wasn't provided). If we didn't find an
2744    *    entry, error out because we can't deal with a frame-wrapped stream
2745    *    without index.
2746    */
2747
2748   offset = klv->offset + klv->consumed;
2749
2750   /* Update the track position (in case of resyncs) */
2751   if (etrack->position == -1) {
2752     GST_DEBUG_OBJECT (demux,
2753         "Unknown essence track position, looking into index");
2754     if (!find_entry_for_offset (demux, etrack, offset - demux->run_in,
2755             &index_entry)) {
2756       GST_WARNING_OBJECT (demux, "Essence track position not in index");
2757       return GST_FLOW_OK;
2758     }
2759     /* Update track position */
2760     etrack->position = index_entry.dts;
2761   } else if (etrack->delta_id == MXF_INDEX_DELTA_ID_UNKNOWN) {
2762     GST_DEBUG_OBJECT (demux,
2763         "Unknown essence track delta_id, looking into index");
2764     if (!find_entry_for_offset (demux, etrack, offset - demux->run_in,
2765             &index_entry)) {
2766       /* Non-fatal, fallback to legacy mode */
2767       GST_WARNING_OBJECT (demux, "Essence track position not in index");
2768     } else if (etrack->position != index_entry.dts) {
2769       GST_ERROR_OBJECT (demux,
2770           "track position doesn't match %" G_GINT64_FORMAT " entry dts %"
2771           G_GINT64_FORMAT, etrack->position, index_entry.dts);
2772       return GST_FLOW_ERROR;
2773     }
2774   } else {
2775     if (!find_edit_entry (demux, etrack, etrack->position, FALSE, &index_entry)) {
2776       GST_DEBUG_OBJECT (demux, "Couldn't find entry");
2777     } else if (etrack->wrapping == MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2778       if (etrack->delta_id != MXF_INDEX_DELTA_ID_IGNORE
2779           && index_entry.offset != offset) {
2780         GST_ERROR_OBJECT (demux,
2781             "demux offset doesn't match %" G_GINT64_FORMAT " entry offset %"
2782             G_GUINT64_FORMAT, offset, index_entry.offset);
2783         return GST_FLOW_ERROR;
2784       }
2785     } else if (index_entry.offset != klv->offset + klv->consumed &&
2786         index_entry.offset != klv->offset + klv->data_offset) {
2787       GST_ERROR_OBJECT (demux,
2788           "KLV offset doesn't match %" G_GINT64_FORMAT " entry offset %"
2789           G_GUINT64_FORMAT, klv->offset + klv->consumed, index_entry.offset);
2790       return GST_FLOW_ERROR;
2791     }
2792   }
2793
2794   if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2795     /* We need entry information to deal with non-frame-wrapped content */
2796     if (!index_entry.initialized) {
2797       GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2798           ("Essence with non-frame-wrapping require an index table to be present"));
2799       return GST_FLOW_ERROR;
2800     }
2801     /* We cannot deal with non-frame-wrapping in push mode for now */
2802     if (!demux->random_access) {
2803       GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2804           ("Non-frame-wrapping is not support in push mode"));
2805       return GST_FLOW_ERROR;
2806     }
2807   }
2808
2809   /* FIXME : If we're peeking and don't need to actually parse the data, we
2810    * should avoid pulling the content from upstream */
2811   if (etrack->wrapping != MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
2812     g_assert (index_entry.size);
2813     GST_DEBUG_OBJECT (demux, "Should only grab %" G_GUINT64_FORMAT " bytes",
2814         index_entry.size);
2815     ret =
2816         gst_mxf_demux_pull_range (demux, index_entry.offset, index_entry.size,
2817         &inbuf);
2818     if (ret != GST_FLOW_OK)
2819       return ret;
2820     if (klv->consumed == 0)
2821       klv->consumed = klv->data_offset + index_entry.size;
2822     else
2823       klv->consumed += index_entry.size;
2824     if (klv != &demux->current_partition->clip_klv)
2825       demux->current_partition->clip_klv = *klv;
2826     GST_LOG_OBJECT (demux,
2827         "klv data_offset:%" G_GUINT64_FORMAT " length:%" G_GSIZE_FORMAT
2828         " consumed:%" G_GUINT64_FORMAT, klv->data_offset, klv->length,
2829         klv->consumed);
2830     /* Switch back to KLV mode if we're done with this one */
2831     if (klv->length + klv->data_offset == klv->consumed)
2832       demux->state = GST_MXF_DEMUX_STATE_KLV;
2833     else
2834       demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
2835   } else {
2836
2837     ret = gst_mxf_demux_fill_klv (demux, klv);
2838     if (ret != GST_FLOW_OK)
2839       return ret;
2840
2841     /* Create subbuffer to be able to change metadata */
2842     inbuf =
2843         gst_buffer_copy_region (klv->data, GST_BUFFER_COPY_ALL, 0,
2844         gst_buffer_get_size (klv->data));
2845
2846   }
2847
2848   if (index_entry.initialized) {
2849     GST_DEBUG_OBJECT (demux, "Got entry dts:%" G_GINT64_FORMAT " keyframe:%d",
2850         index_entry.dts, index_entry.keyframe);
2851   }
2852   if (index_entry.initialized && !index_entry.keyframe)
2853     GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT);
2854
2855   if (etrack->handle_func) {
2856     /* Takes ownership of inbuf */
2857     ret =
2858         etrack->handle_func (&klv->key, inbuf, etrack->caps,
2859         etrack->source_track, etrack->mapping_data, &outbuf);
2860     inbuf = NULL;
2861   } else {
2862     outbuf = inbuf;
2863     inbuf = NULL;
2864     ret = GST_FLOW_OK;
2865   }
2866
2867   if (ret != GST_FLOW_OK) {
2868     GST_ERROR_OBJECT (demux, "Failed to handle essence element");
2869     if (outbuf) {
2870       gst_buffer_unref (outbuf);
2871       outbuf = NULL;
2872     }
2873     return ret;
2874   }
2875
2876   if (!index_entry.initialized) {
2877     /* This can happen when doing scanning without entry tables */
2878     index_entry.duration = 1;
2879     index_entry.offset = demux->offset - demux->run_in;
2880     index_entry.dts = etrack->position;
2881     index_entry.pts = etrack->intra_only ? etrack->position : G_MAXUINT64;
2882     index_entry.keyframe =
2883         !GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
2884     index_entry.initialized = TRUE;
2885     GST_DEBUG_OBJECT (demux,
2886         "Storing newly discovered information on track %d. dts: %"
2887         G_GINT64_FORMAT " offset:%" G_GUINT64_FORMAT " keyframe:%d",
2888         etrack->track_id, index_entry.dts, index_entry.offset,
2889         index_entry.keyframe);
2890
2891     if (!etrack->offsets)
2892       etrack->offsets = g_array_new (FALSE, TRUE, sizeof (GstMXFDemuxIndex));
2893
2894     /* We only ever append to the track offset entry. */
2895     g_assert (etrack->position <= etrack->offsets->len);
2896     g_array_insert_val (etrack->offsets, etrack->position, index_entry);
2897   }
2898
2899   if (peek)
2900     goto out;
2901
2902   if (!outbuf) {
2903     GST_DEBUG_OBJECT (demux, "No output buffer created");
2904     goto out;
2905   }
2906
2907   inbuf = outbuf;
2908   outbuf = NULL;
2909
2910   max_temporal_offset = get_track_max_temporal_offset (demux, etrack);
2911
2912   for (i = 0; i < demux->src->len; i++) {
2913     GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
2914
2915     if (pad->current_essence_track != etrack)
2916       continue;
2917
2918     if (pad->eos) {
2919       GST_DEBUG_OBJECT (pad, "Pad is already EOS");
2920       continue;
2921     }
2922
2923     if (etrack->position < pad->current_essence_track_position) {
2924       GST_DEBUG_OBJECT (pad,
2925           "Not at current component's position (track:%" G_GINT64_FORMAT
2926           " essence:%" G_GINT64_FORMAT ")", etrack->position,
2927           pad->current_essence_track_position);
2928       continue;
2929     }
2930
2931     {
2932       GstMXFDemuxPad *earliest = gst_mxf_demux_get_earliest_pad (demux);
2933
2934       if (earliest && earliest != pad && earliest->position < pad->position &&
2935           pad->position - earliest->position > demux->max_drift) {
2936         GST_DEBUG_OBJECT (earliest,
2937             "Pad is too far ahead of time (%" GST_TIME_FORMAT " vs earliest:%"
2938             GST_TIME_FORMAT ")", GST_TIME_ARGS (earliest->position),
2939             GST_TIME_ARGS (pad->position));
2940         continue;
2941       }
2942     }
2943
2944     /* Create another subbuffer to have writable metadata */
2945     outbuf =
2946         gst_buffer_copy_region (inbuf, GST_BUFFER_COPY_ALL, 0,
2947         gst_buffer_get_size (inbuf));
2948
2949     pts = index_entry.pts;
2950
2951     GST_BUFFER_DTS (outbuf) = pad->position;
2952     if (etrack->intra_only) {
2953       GST_BUFFER_PTS (outbuf) = pad->position;
2954     } else if (pts != G_MAXUINT64) {
2955       GST_BUFFER_PTS (outbuf) = gst_util_uint64_scale (pts * GST_SECOND,
2956           pad->current_essence_track->source_track->edit_rate.d,
2957           pad->current_essence_track->source_track->edit_rate.n);
2958       GST_BUFFER_PTS (outbuf) +=
2959           gst_util_uint64_scale (pad->current_component_start_position *
2960           GST_SECOND, pad->material_track->edit_rate.d,
2961           pad->material_track->edit_rate.n);
2962       /* We are dealing with reordered data, the PTS is shifted forward by the
2963        * maximum temporal reordering (the DTS remain as-is). */
2964       if (max_temporal_offset > 0)
2965         GST_BUFFER_PTS (outbuf) +=
2966             gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
2967             pad->current_essence_track->source_track->edit_rate.d,
2968             pad->current_essence_track->source_track->edit_rate.n);
2969
2970     } else {
2971       GST_BUFFER_PTS (outbuf) = GST_CLOCK_TIME_NONE;
2972     }
2973
2974     GST_BUFFER_DURATION (outbuf) =
2975         gst_util_uint64_scale (GST_SECOND,
2976         index_entry.duration *
2977         pad->current_essence_track->source_track->edit_rate.d,
2978         pad->current_essence_track->source_track->edit_rate.n);
2979     GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
2980     GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
2981
2982     if (pad->material_track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE
2983         && pad->start_timecode.config.fps_n != 0
2984         && pad->start_timecode.config.fps_d != 0) {
2985       if (etrack->intra_only) {
2986         GstVideoTimeCode timecode = pad->start_timecode;
2987
2988         gst_video_time_code_add_frames (&timecode,
2989             pad->current_material_track_position);
2990         gst_buffer_add_video_time_code_meta (outbuf, &timecode);
2991       } else if (pts != G_MAXUINT64) {
2992         GstVideoTimeCode timecode = pad->start_timecode;
2993
2994         gst_video_time_code_add_frames (&timecode,
2995             pad->current_component_start_position);
2996         gst_video_time_code_add_frames (&timecode,
2997             gst_util_uint64_scale (pts,
2998                 pad->material_track->edit_rate.n *
2999                 pad->current_essence_track->source_track->edit_rate.d,
3000                 pad->material_track->edit_rate.d *
3001                 pad->current_essence_track->source_track->edit_rate.n));
3002         gst_buffer_add_video_time_code_meta (outbuf, &timecode);
3003       }
3004
3005     }
3006
3007     /* Update accumulated error and compensate */
3008     {
3009       guint64 abs_error =
3010           (GST_SECOND * pad->current_essence_track->source_track->edit_rate.d) %
3011           pad->current_essence_track->source_track->edit_rate.n;
3012       pad->position_accumulated_error +=
3013           ((gdouble) abs_error) /
3014           ((gdouble) pad->current_essence_track->source_track->edit_rate.n);
3015     }
3016     if (pad->position_accumulated_error >= 1.0) {
3017       GST_BUFFER_DURATION (outbuf) += 1;
3018       pad->position_accumulated_error -= 1.0;
3019     }
3020
3021     if (pad->need_segment) {
3022       GstEvent *e;
3023
3024       if (demux->close_seg_event)
3025         gst_pad_push_event (GST_PAD_CAST (pad),
3026             gst_event_ref (demux->close_seg_event));
3027
3028       if (max_temporal_offset > 0) {
3029         GstSegment shift_segment;
3030         /* Handle maximum temporal offset. We are shifting all output PTS for
3031          * this stream by the greatest temporal reordering that can occur. In
3032          * order not to change the stream/running time we shift the segment
3033          * start and stop values accordingly */
3034         gst_segment_copy_into (&demux->segment, &shift_segment);
3035         if (GST_CLOCK_TIME_IS_VALID (shift_segment.start))
3036           shift_segment.start +=
3037               gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
3038               pad->current_essence_track->source_track->edit_rate.d,
3039               pad->current_essence_track->source_track->edit_rate.n);
3040         if (GST_CLOCK_TIME_IS_VALID (shift_segment.stop))
3041           shift_segment.stop +=
3042               gst_util_uint64_scale (max_temporal_offset * GST_SECOND,
3043               pad->current_essence_track->source_track->edit_rate.d,
3044               pad->current_essence_track->source_track->edit_rate.n);
3045         e = gst_event_new_segment (&shift_segment);
3046       } else
3047         e = gst_event_new_segment (&demux->segment);
3048       GST_DEBUG_OBJECT (pad, "Sending segment %" GST_PTR_FORMAT, e);
3049       gst_event_set_seqnum (e, demux->seqnum);
3050       gst_pad_push_event (GST_PAD_CAST (pad), e);
3051       pad->need_segment = FALSE;
3052     }
3053
3054     if (pad->tags) {
3055       gst_pad_push_event (GST_PAD_CAST (pad), gst_event_new_tag (pad->tags));
3056       pad->tags = NULL;
3057     }
3058
3059     pad->position += GST_BUFFER_DURATION (outbuf);
3060     pad->current_material_track_position += index_entry.duration;
3061
3062     if (pad->discont) {
3063       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
3064       pad->discont = FALSE;
3065     }
3066
3067     /* Handlers can provide empty GAP buffers to indicate that the parsed
3068      * content was valid but that nothing meaningful needs to be outputted. In
3069      * such cases we send out a GAP event instead */
3070     if (GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP) &&
3071         gst_buffer_get_size (outbuf) == 0) {
3072       GstEvent *gap = gst_event_new_gap (GST_BUFFER_DTS (outbuf),
3073           GST_BUFFER_DURATION (outbuf));
3074       gst_buffer_unref (outbuf);
3075       GST_DEBUG_OBJECT (pad,
3076           "Replacing empty gap buffer with gap event %" GST_PTR_FORMAT, gap);
3077       gst_pad_push_event (GST_PAD_CAST (pad), gap);
3078     } else {
3079       GST_DEBUG_OBJECT (pad,
3080           "Pushing buffer of size %" G_GSIZE_FORMAT " for track %u: pts %"
3081           GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT
3082           " position %" G_GUINT64_FORMAT, gst_buffer_get_size (outbuf),
3083           pad->material_track->parent.track_id,
3084           GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)),
3085           GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
3086           GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
3087           pad->current_essence_track_position);
3088
3089       ret = gst_pad_push (GST_PAD_CAST (pad), outbuf);
3090     }
3091     outbuf = NULL;
3092     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
3093     GST_LOG_OBJECT (pad, "combined return %s", gst_flow_get_name (ret));
3094
3095     if (pad->position > demux->segment.position)
3096       demux->segment.position = pad->position;
3097
3098     if (ret != GST_FLOW_OK)
3099       goto out;
3100
3101     pad->current_essence_track_position += index_entry.duration;
3102
3103     if (pad->current_component) {
3104       if (pad->current_component_duration > 0 &&
3105           pad->current_essence_track_position - pad->current_component_start
3106           >= pad->current_component_duration) {
3107         GST_DEBUG_OBJECT (demux, "Switching to next component");
3108
3109         ret =
3110             gst_mxf_demux_pad_set_component (demux, pad,
3111             pad->current_component_index + 1);
3112         if (ret == GST_FLOW_OK) {
3113           pad->current_essence_track->position =
3114               pad->current_essence_track_position;
3115         } else if (ret != GST_FLOW_EOS) {
3116           GST_ERROR_OBJECT (demux, "Switching component failed");
3117         }
3118       } else if (etrack->duration > 0
3119           && pad->current_essence_track_position >= etrack->duration) {
3120         GST_DEBUG_OBJECT (demux,
3121             "Current component position after end of essence track");
3122         ret = GST_FLOW_EOS;
3123       }
3124     } else if (etrack->duration > 0
3125         && pad->current_essence_track_position == etrack->duration) {
3126       GST_DEBUG_OBJECT (demux, "At the end of the essence track");
3127       ret = GST_FLOW_EOS;
3128     }
3129
3130     if (ret == GST_FLOW_EOS) {
3131       GstEvent *e;
3132
3133       GST_DEBUG_OBJECT (pad, "EOS for track");
3134       pad->eos = TRUE;
3135       e = gst_event_new_eos ();
3136       gst_event_set_seqnum (e, demux->seqnum);
3137       gst_pad_push_event (GST_PAD_CAST (pad), e);
3138       ret = GST_FLOW_OK;
3139     }
3140
3141     if (ret != GST_FLOW_OK)
3142       goto out;
3143   }
3144
3145 out:
3146   if (inbuf)
3147     gst_buffer_unref (inbuf);
3148
3149   if (outbuf)
3150     gst_buffer_unref (outbuf);
3151
3152   etrack->position += index_entry.duration;
3153
3154   return ret;
3155 }
3156
3157 /*
3158  * Called when analyzing the (RIP) Random Index Pack.
3159  *
3160  * FIXME : If a file doesn't have a RIP, we should iterate the partition headers
3161  * to collect as much information as possible.
3162  *
3163  * This function collects as much information as possible from the partition headers:
3164  * * Store partition information in the list of partitions
3165  * * Handle any index table segment present
3166  */
3167 static void
3168 read_partition_header (GstMXFDemux * demux)
3169 {
3170   GstMXFKLV klv;
3171
3172   if (gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv) != GST_FLOW_OK
3173       || !mxf_is_partition_pack (&klv.key)) {
3174     return;
3175   }
3176
3177   if (gst_mxf_demux_handle_partition_pack (demux, &klv) != GST_FLOW_OK) {
3178     if (klv.data)
3179       gst_buffer_unref (klv.data);
3180     return;
3181   }
3182   gst_mxf_demux_consume_klv (demux, &klv);
3183
3184   if (gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv) != GST_FLOW_OK)
3185     return;
3186
3187   while (mxf_is_fill (&klv.key)) {
3188     gst_mxf_demux_consume_klv (demux, &klv);
3189     if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3190             &klv) != GST_FLOW_OK)
3191       return;
3192   }
3193
3194   if (!mxf_is_index_table_segment (&klv.key)
3195       && demux->current_partition->partition.header_byte_count) {
3196     demux->offset += demux->current_partition->partition.header_byte_count;
3197     if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3198             &klv) != GST_FLOW_OK)
3199       return;
3200   }
3201
3202   while (mxf_is_fill (&klv.key)) {
3203     gst_mxf_demux_consume_klv (demux, &klv);
3204     if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3205             &klv) != GST_FLOW_OK)
3206       return;
3207   }
3208
3209   if (demux->current_partition->partition.index_byte_count
3210       && mxf_is_index_table_segment (&klv.key)) {
3211     guint64 index_end_offset =
3212         demux->offset + demux->current_partition->partition.index_byte_count;
3213
3214     while (demux->offset < index_end_offset) {
3215       if (mxf_is_index_table_segment (&klv.key))
3216         gst_mxf_demux_handle_index_table_segment (demux, &klv);
3217       gst_mxf_demux_consume_klv (demux, &klv);
3218
3219       if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3220               &klv) != GST_FLOW_OK)
3221         return;
3222     }
3223   }
3224
3225   while (mxf_is_fill (&klv.key)) {
3226     gst_mxf_demux_consume_klv (demux, &klv);
3227     if (gst_mxf_demux_peek_klv_packet (demux, demux->offset,
3228             &klv) != GST_FLOW_OK)
3229       return;
3230   }
3231
3232   if (mxf_is_generic_container_system_item (&klv.key) ||
3233       mxf_is_generic_container_essence_element (&klv.key) ||
3234       mxf_is_avid_essence_container_essence_element (&klv.key)) {
3235     if (demux->current_partition->essence_container_offset == 0)
3236       demux->current_partition->essence_container_offset =
3237           demux->offset - demux->current_partition->partition.this_partition -
3238           demux->run_in;
3239   }
3240 }
3241
3242 static GstFlowReturn
3243 gst_mxf_demux_handle_random_index_pack (GstMXFDemux * demux, GstMXFKLV * klv)
3244 {
3245   guint i;
3246   GList *l;
3247   GstMapInfo map;
3248   gboolean ret;
3249   GstFlowReturn flowret;
3250
3251   GST_DEBUG_OBJECT (demux,
3252       "Handling random index pack of size %" G_GSIZE_FORMAT " at offset %"
3253       G_GUINT64_FORMAT, klv->length, klv->offset);
3254
3255   if (demux->random_index_pack) {
3256     GST_DEBUG_OBJECT (demux, "Already parsed random index pack");
3257     return GST_FLOW_OK;
3258   }
3259
3260   flowret = gst_mxf_demux_fill_klv (demux, klv);
3261   if (flowret != GST_FLOW_OK)
3262     return flowret;
3263
3264   gst_buffer_map (klv->data, &map, GST_MAP_READ);
3265   ret =
3266       mxf_random_index_pack_parse (&klv->key, map.data, map.size,
3267       &demux->random_index_pack);
3268   gst_buffer_unmap (klv->data, &map);
3269
3270   if (!ret) {
3271     GST_ERROR_OBJECT (demux, "Parsing random index pack failed");
3272     return GST_FLOW_ERROR;
3273   }
3274
3275   for (i = 0; i < demux->random_index_pack->len; i++) {
3276     GstMXFDemuxPartition *p = NULL;
3277     MXFRandomIndexPackEntry *e =
3278         &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry, i);
3279
3280     if (e->offset < demux->run_in) {
3281       GST_ERROR_OBJECT (demux, "Invalid random index pack entry");
3282       return GST_FLOW_ERROR;
3283     }
3284
3285     for (l = demux->partitions; l; l = l->next) {
3286       GstMXFDemuxPartition *tmp = l->data;
3287
3288       if (tmp->partition.this_partition + demux->run_in == e->offset) {
3289         p = tmp;
3290         break;
3291       }
3292     }
3293
3294     if (!p) {
3295       p = g_new0 (GstMXFDemuxPartition, 1);
3296       p->partition.this_partition = e->offset - demux->run_in;
3297       p->partition.body_sid = e->body_sid;
3298       demux->partitions =
3299           g_list_insert_sorted (demux->partitions, p,
3300           (GCompareFunc) gst_mxf_demux_partition_compare);
3301     }
3302   }
3303
3304   for (l = demux->partitions; l; l = l->next) {
3305     GstMXFDemuxPartition *a, *b;
3306
3307     if (l->next == NULL)
3308       break;
3309
3310     a = l->data;
3311     b = l->next->data;
3312
3313     b->partition.prev_partition = a->partition.this_partition;
3314   }
3315
3316   return GST_FLOW_OK;
3317 }
3318
3319 static gint
3320 compare_index_table_segment (MXFIndexTableSegment * sa,
3321     MXFIndexTableSegment * sb)
3322 {
3323   if (sa->body_sid != sb->body_sid)
3324     return (sa->body_sid < sb->body_sid) ? -1 : 1;
3325   if (sa->index_sid != sb->index_sid)
3326     return (sa->index_sid < sb->index_sid) ? -1 : 1;
3327   if (sa->index_start_position != sb->index_start_position)
3328     return (sa->index_start_position < sb->index_start_position) ? -1 : 1;
3329
3330   /* If all the above are equal ... the index table segments are only equal if
3331    * their instance ID are equal. Until March 2022 the FFmpeg MXF muxer would
3332    * write the same instance id for the various (different) index table
3333    * segments, we therefore only check instance ID *after* all the above
3334    * properties to make sure they are really different. */
3335   if (mxf_uuid_is_equal (&sa->instance_id, &sb->instance_id))
3336     return 0;
3337
3338   return 1;
3339 }
3340
3341 static GstFlowReturn
3342 gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux, GstMXFKLV * klv)
3343 {
3344   MXFIndexTableSegment *segment;
3345   GstMapInfo map;
3346   gboolean ret;
3347   GList *tmp;
3348   GstFlowReturn flowret;
3349
3350   flowret = gst_mxf_demux_fill_klv (demux, klv);
3351   if (flowret != GST_FLOW_OK)
3352     return flowret;
3353
3354   GST_DEBUG_OBJECT (demux,
3355       "Handling index table segment of size %" G_GSIZE_FORMAT " at offset %"
3356       G_GUINT64_FORMAT, klv->length, klv->offset);
3357
3358   segment = g_new0 (MXFIndexTableSegment, 1);
3359
3360   gst_buffer_map (klv->data, &map, GST_MAP_READ);
3361   ret = mxf_index_table_segment_parse (&klv->key, segment, map.data, map.size);
3362   gst_buffer_unmap (klv->data, &map);
3363
3364   if (!ret) {
3365     GST_ERROR_OBJECT (demux, "Parsing index table segment failed");
3366     g_free (segment);
3367     return GST_FLOW_ERROR;
3368   }
3369
3370   /* Drop it if we already saw it. Ideally we should be able to do this before
3371      parsing (by checking instance UID) */
3372   if (g_list_find_custom (demux->pending_index_table_segments, segment,
3373           (GCompareFunc) compare_index_table_segment)) {
3374     GST_DEBUG_OBJECT (demux, "Already in pending list");
3375     mxf_index_table_segment_reset (segment);
3376     g_free (segment);
3377     return GST_FLOW_OK;
3378   }
3379   for (tmp = demux->index_tables; tmp; tmp = tmp->next) {
3380     GstMXFDemuxIndexTable *table = (GstMXFDemuxIndexTable *) tmp->data;
3381     if (g_array_binary_search (table->segments, segment,
3382             (GCompareFunc) compare_index_table_segment, NULL)) {
3383       GST_DEBUG_OBJECT (demux, "Already handled");
3384       mxf_index_table_segment_reset (segment);
3385       g_free (segment);
3386       return GST_FLOW_OK;
3387     }
3388   }
3389
3390   demux->pending_index_table_segments =
3391       g_list_insert_sorted (demux->pending_index_table_segments, segment,
3392       (GCompareFunc) compare_index_table_segment);
3393
3394   return GST_FLOW_OK;
3395 }
3396
3397 static GstFlowReturn
3398 gst_mxf_demux_peek_klv_packet (GstMXFDemux * demux, guint64 offset,
3399     GstMXFKLV * klv)
3400 {
3401   GstBuffer *buffer = NULL;
3402   const guint8 *data;
3403   GstFlowReturn ret = GST_FLOW_OK;
3404   GstMapInfo map;
3405 #ifndef GST_DISABLE_GST_DEBUG
3406   gchar str[48];
3407 #endif
3408
3409   memset (klv, 0, sizeof (GstMXFKLV));
3410   klv->offset = offset;
3411
3412   /* Pull 16 byte key and first byte of BER encoded length */
3413   if ((ret =
3414           gst_mxf_demux_pull_range (demux, offset, 17, &buffer)) != GST_FLOW_OK)
3415     goto beach;
3416
3417   gst_buffer_map (buffer, &map, GST_MAP_READ);
3418
3419   memcpy (&klv->key, map.data, 16);
3420
3421   /* Decode BER encoded packet length */
3422   if ((map.data[16] & 0x80) == 0) {
3423     klv->length = map.data[16];
3424     klv->data_offset = 17;
3425   } else {
3426     guint slen = map.data[16] & 0x7f;
3427
3428     klv->data_offset = 16 + 1 + slen;
3429
3430     gst_buffer_unmap (buffer, &map);
3431     gst_buffer_unref (buffer);
3432     buffer = NULL;
3433
3434     /* Must be at most 8 according to SMPTE-379M 5.3.4 */
3435     if (slen > 8) {
3436       GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
3437       ret = GST_FLOW_ERROR;
3438       goto beach;
3439     }
3440
3441     /* Now pull the length of the packet */
3442     if ((ret = gst_mxf_demux_pull_range (demux, offset + 17, slen,
3443                 &buffer)) != GST_FLOW_OK)
3444       goto beach;
3445
3446     gst_buffer_map (buffer, &map, GST_MAP_READ);
3447
3448     data = map.data;
3449     klv->length = 0;
3450     while (slen) {
3451       klv->length = (klv->length << 8) | *data;
3452       data++;
3453       slen--;
3454     }
3455   }
3456
3457   gst_buffer_unmap (buffer, &map);
3458   gst_buffer_unref (buffer);
3459   buffer = NULL;
3460
3461   /* GStreamer's buffer sizes are stored in a guint so we
3462    * limit ourself to G_MAXUINT large buffers */
3463   if (klv->length > G_MAXUINT) {
3464     GST_ERROR_OBJECT (demux,
3465         "Unsupported KLV packet length: %" G_GSIZE_FORMAT, klv->length);
3466     ret = GST_FLOW_ERROR;
3467     goto beach;
3468   }
3469
3470   GST_DEBUG_OBJECT (demux,
3471       "Found KLV packet at offset %" G_GUINT64_FORMAT " with key %s and length "
3472       "%" G_GSIZE_FORMAT, offset, mxf_ul_to_string (&klv->key, str),
3473       klv->length);
3474
3475 beach:
3476   if (buffer)
3477     gst_buffer_unref (buffer);
3478
3479   return ret;
3480 }
3481
3482 static GstFlowReturn
3483 gst_mxf_demux_fill_klv (GstMXFDemux * demux, GstMXFKLV * klv)
3484 {
3485   if (klv->data)
3486     return GST_FLOW_OK;
3487   GST_DEBUG_OBJECT (demux,
3488       "Pulling %" G_GSIZE_FORMAT " bytes from offset %" G_GUINT64_FORMAT,
3489       klv->length, klv->offset + klv->data_offset);
3490   return gst_mxf_demux_pull_range (demux, klv->offset + klv->data_offset,
3491       klv->length, &klv->data);
3492 }
3493
3494 /* Call when done with a klv. Will release the buffer (if any) and will update
3495  * the demuxer offset position. Do *NOT* call if you do not want the demuxer
3496  * offset to be updated */
3497 static void
3498 gst_mxf_demux_consume_klv (GstMXFDemux * demux, GstMXFKLV * klv)
3499 {
3500   if (klv->data) {
3501     gst_buffer_unref (klv->data);
3502     klv->data = NULL;
3503   }
3504   GST_DEBUG_OBJECT (demux,
3505       "Consuming KLV offset:%" G_GUINT64_FORMAT " data_offset:%"
3506       G_GUINT64_FORMAT " length:%" G_GSIZE_FORMAT " consumed:%"
3507       G_GUINT64_FORMAT, klv->offset, klv->data_offset, klv->length,
3508       klv->consumed);
3509   if (klv->consumed)
3510     demux->offset = klv->offset + klv->consumed;
3511   else
3512     demux->offset += klv->data_offset + klv->length;
3513 }
3514
3515 static void
3516 gst_mxf_demux_pull_random_index_pack (GstMXFDemux * demux)
3517 {
3518   GstBuffer *buffer;
3519   gint64 filesize = -1;
3520   GstFormat fmt = GST_FORMAT_BYTES;
3521   guint32 pack_size;
3522   guint64 old_offset = demux->offset;
3523   GstMapInfo map;
3524   GstFlowReturn flow_ret;
3525   GstMXFKLV klv;
3526
3527   if (!gst_pad_peer_query_duration (demux->sinkpad, fmt, &filesize) ||
3528       fmt != GST_FORMAT_BYTES || filesize == -1) {
3529     GST_DEBUG_OBJECT (demux, "Can't query upstream size");
3530     return;
3531   }
3532
3533   g_assert (filesize > 4);
3534
3535   buffer = NULL;
3536   if (gst_mxf_demux_pull_range (demux, filesize - 4, 4, &buffer) != GST_FLOW_OK) {
3537     GST_DEBUG_OBJECT (demux, "Failed pulling last 4 bytes");
3538     return;
3539   }
3540
3541   gst_buffer_map (buffer, &map, GST_MAP_READ);
3542   pack_size = GST_READ_UINT32_BE (map.data);
3543   gst_buffer_unmap (buffer, &map);
3544
3545   gst_buffer_unref (buffer);
3546
3547   if (pack_size < 20) {
3548     GST_DEBUG_OBJECT (demux, "Too small pack size (%u bytes)", pack_size);
3549     return;
3550   } else if (pack_size > filesize - 20) {
3551     GST_DEBUG_OBJECT (demux, "Too large pack size (%u bytes)", pack_size);
3552     return;
3553   }
3554
3555   /* Peek for klv at filesize - pack_size */
3556   if (gst_mxf_demux_peek_klv_packet (demux, filesize - pack_size,
3557           &klv) != GST_FLOW_OK) {
3558     GST_DEBUG_OBJECT (demux, "Failed pulling random index pack key");
3559     return;
3560   }
3561
3562   if (!mxf_is_random_index_pack (&klv.key)) {
3563     GST_DEBUG_OBJECT (demux, "No random index pack");
3564     return;
3565   }
3566
3567   demux->offset = filesize - pack_size;
3568   flow_ret = gst_mxf_demux_handle_random_index_pack (demux, &klv);
3569   if (klv.data)
3570     gst_buffer_unref (klv.data);
3571   demux->offset = old_offset;
3572
3573   if (flow_ret == GST_FLOW_OK && !demux->index_table_segments_collected) {
3574     collect_index_table_segments (demux);
3575     demux->index_table_segments_collected = TRUE;
3576   }
3577 }
3578
3579 static void
3580 gst_mxf_demux_parse_footer_metadata (GstMXFDemux * demux)
3581 {
3582   guint64 old_offset = demux->offset;
3583   GstMXFKLV klv;
3584   GstFlowReturn flow = GST_FLOW_OK;
3585   GstMXFDemuxPartition *old_partition = demux->current_partition;
3586
3587   GST_DEBUG_OBJECT (demux, "Parsing footer metadata");
3588
3589   demux->current_partition = NULL;
3590
3591   gst_mxf_demux_reset_metadata (demux);
3592
3593   if (demux->footer_partition_pack_offset != 0) {
3594     demux->offset = demux->run_in + demux->footer_partition_pack_offset;
3595   } else {
3596     MXFRandomIndexPackEntry *entry =
3597         &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry,
3598         demux->random_index_pack->len - 1);
3599     demux->offset = entry->offset;
3600   }
3601
3602 next_try:
3603   GST_LOG_OBJECT (demux, "Peeking partition pack at offset %" G_GUINT64_FORMAT,
3604       demux->offset);
3605
3606   /* Process Partition Pack */
3607   flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3608   if (G_UNLIKELY (flow != GST_FLOW_OK))
3609     goto out;
3610
3611   if (!mxf_is_partition_pack (&klv.key))
3612     goto out;
3613
3614   if (gst_mxf_demux_handle_partition_pack (demux, &klv) != GST_FLOW_OK) {
3615     if (klv.data)
3616       gst_buffer_unref (klv.data);
3617     goto out;
3618   }
3619
3620   gst_mxf_demux_consume_klv (demux, &klv);
3621
3622   /* If there's no Header Metadata in this partition, jump to the previous
3623    * one */
3624   if (demux->current_partition->partition.header_byte_count == 0) {
3625     /* Reached the first partition, bail out */
3626     if (demux->current_partition->partition.this_partition == 0)
3627       goto out;
3628
3629     demux->offset =
3630         demux->run_in + demux->current_partition->partition.prev_partition;
3631     goto next_try;
3632   }
3633
3634   /* Next up should be an optional fill pack followed by a primer pack */
3635   while (TRUE) {
3636     flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3637     if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3638       /* If ever we can't get the next KLV, jump to the previous partition */
3639       if (!demux->current_partition->partition.prev_partition)
3640         goto out;
3641       demux->offset =
3642           demux->run_in + demux->current_partition->partition.prev_partition;
3643       goto next_try;
3644     }
3645
3646     if (mxf_is_fill (&klv.key)) {
3647       gst_mxf_demux_consume_klv (demux, &klv);
3648     } else if (mxf_is_primer_pack (&klv.key)) {
3649       /* Update primer mapping if present (jump to previous if it failed) */
3650       if (!demux->current_partition->primer.mappings) {
3651         if (gst_mxf_demux_handle_primer_pack (demux, &klv) != GST_FLOW_OK) {
3652           gst_mxf_demux_consume_klv (demux, &klv);
3653           if (!demux->current_partition->partition.prev_partition)
3654             goto out;
3655           demux->offset =
3656               demux->run_in +
3657               demux->current_partition->partition.prev_partition;
3658           goto next_try;
3659         }
3660       }
3661       gst_mxf_demux_consume_klv (demux, &klv);
3662       break;
3663     } else {
3664       if (!demux->current_partition->partition.prev_partition)
3665         goto out;
3666       demux->offset =
3667           demux->run_in + demux->current_partition->partition.prev_partition;
3668       goto next_try;
3669     }
3670   }
3671
3672   /* parse metadata for this partition */
3673   while (demux->offset <
3674       demux->run_in + demux->current_partition->primer.offset +
3675       demux->current_partition->partition.header_byte_count) {
3676     flow = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3677     if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3678       if (!demux->current_partition->partition.prev_partition)
3679         goto out;
3680       demux->offset =
3681           demux->run_in + demux->current_partition->partition.prev_partition;
3682       goto next_try;
3683     }
3684
3685     if (mxf_is_metadata (&klv.key)) {
3686       flow = gst_mxf_demux_handle_metadata (demux, &klv);
3687       gst_mxf_demux_consume_klv (demux, &klv);
3688
3689       if (G_UNLIKELY (flow != GST_FLOW_OK)) {
3690         gst_mxf_demux_reset_metadata (demux);
3691         if (!demux->current_partition->partition.prev_partition)
3692           goto out;
3693         demux->offset =
3694             demux->run_in + demux->current_partition->partition.prev_partition;
3695         goto next_try;
3696       }
3697     } else if (mxf_is_descriptive_metadata (&klv.key)) {
3698       gst_mxf_demux_handle_descriptive_metadata (demux, &klv);
3699       gst_mxf_demux_consume_klv (demux, &klv);
3700     } else {
3701       gst_mxf_demux_consume_klv (demux, &klv);
3702     }
3703   }
3704
3705   /* resolve references etc */
3706   if (!demux->preface || gst_mxf_demux_resolve_references (demux) !=
3707       GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
3708     /* Don't attempt to parse metadata from this partition again */
3709     demux->current_partition->parsed_metadata = TRUE;
3710     /* Skip to previous partition or bail out */
3711     if (!demux->current_partition->partition.prev_partition)
3712       goto out;
3713     demux->offset =
3714         demux->run_in + demux->current_partition->partition.prev_partition;
3715     goto next_try;
3716   }
3717
3718 out:
3719   demux->offset = old_offset;
3720   demux->current_partition = old_partition;
3721 }
3722
3723 static GstFlowReturn
3724 gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, GstMXFKLV * klv,
3725     gboolean peek)
3726 {
3727   MXFUL *key = &klv->key;
3728 #ifndef GST_DISABLE_GST_DEBUG
3729   gchar key_str[48];
3730 #endif
3731   GstFlowReturn ret = GST_FLOW_OK;
3732
3733   if (demux->update_metadata
3734       && demux->preface
3735       && (demux->offset >=
3736           demux->run_in + demux->current_partition->primer.offset +
3737           demux->current_partition->partition.header_byte_count ||
3738           mxf_is_generic_container_system_item (key) ||
3739           mxf_is_generic_container_essence_element (key) ||
3740           mxf_is_avid_essence_container_essence_element (key))) {
3741     demux->current_partition->parsed_metadata = TRUE;
3742     if ((ret = gst_mxf_demux_resolve_references (demux)) != GST_FLOW_OK ||
3743         (ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
3744       goto beach;
3745     }
3746   } else if (demux->metadata_resolved && demux->requested_package_string) {
3747     if ((ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
3748       goto beach;
3749     }
3750   }
3751
3752   if (!mxf_is_mxf_packet (key)) {
3753     GST_WARNING_OBJECT (demux,
3754         "Skipping non-MXF packet of size %" G_GSIZE_FORMAT " at offset %"
3755         G_GUINT64_FORMAT ", key: %s", klv->length,
3756         demux->offset, mxf_ul_to_string (key, key_str));
3757   } else if (mxf_is_partition_pack (key)) {
3758     ret = gst_mxf_demux_handle_partition_pack (demux, klv);
3759   } else if (mxf_is_primer_pack (key)) {
3760     ret = gst_mxf_demux_handle_primer_pack (demux, klv);
3761   } else if (mxf_is_metadata (key)) {
3762     ret = gst_mxf_demux_handle_metadata (demux, klv);
3763   } else if (mxf_is_descriptive_metadata (key)) {
3764     ret = gst_mxf_demux_handle_descriptive_metadata (demux, klv);
3765   } else if (mxf_is_generic_container_system_item (key)) {
3766     if (demux->pending_index_table_segments)
3767       collect_index_table_segments (demux);
3768     ret = gst_mxf_demux_handle_generic_container_system_item (demux, klv);
3769   } else if (mxf_is_generic_container_essence_element (key) ||
3770       mxf_is_avid_essence_container_essence_element (key)) {
3771     if (demux->pending_index_table_segments)
3772       collect_index_table_segments (demux);
3773     ret =
3774         gst_mxf_demux_handle_generic_container_essence_element (demux, klv,
3775         peek);
3776   } else if (mxf_is_random_index_pack (key)) {
3777     ret = gst_mxf_demux_handle_random_index_pack (demux, klv);
3778
3779     if (ret == GST_FLOW_OK && demux->random_access
3780         && !demux->index_table_segments_collected) {
3781       collect_index_table_segments (demux);
3782       demux->index_table_segments_collected = TRUE;
3783     }
3784   } else if (mxf_is_index_table_segment (key)) {
3785     ret = gst_mxf_demux_handle_index_table_segment (demux, klv);
3786   } else if (mxf_is_fill (key)) {
3787     GST_DEBUG_OBJECT (demux,
3788         "Skipping filler packet of size %" G_GSIZE_FORMAT " at offset %"
3789         G_GUINT64_FORMAT, klv->length, demux->offset);
3790   } else {
3791     GST_DEBUG_OBJECT (demux,
3792         "Skipping unknown packet of size %" G_GSIZE_FORMAT " at offset %"
3793         G_GUINT64_FORMAT ", key: %s", klv->length,
3794         demux->offset, mxf_ul_to_string (key, key_str));
3795   }
3796
3797 beach:
3798   return ret;
3799 }
3800
3801 static void
3802 gst_mxf_demux_set_partition_for_offset (GstMXFDemux * demux, guint64 offset)
3803 {
3804   GList *l;
3805
3806   GST_LOG_OBJECT (demux, "offset %" G_GUINT64_FORMAT, offset);
3807
3808   /* This partition will already be parsed, otherwise
3809    * the position wouldn't be in the index */
3810   for (l = demux->partitions; l; l = l->next) {
3811     GstMXFDemuxPartition *p = l->data;
3812
3813     if (p->partition.this_partition + demux->run_in <= offset)
3814       demux->current_partition = p;
3815   }
3816   if (demux->current_partition)
3817     GST_DEBUG_OBJECT (demux,
3818         "Current partition now %p (body_sid:%d index_sid:%d this_partition:%"
3819         G_GUINT64_FORMAT ")", demux->current_partition,
3820         demux->current_partition->partition.body_sid,
3821         demux->current_partition->partition.index_sid,
3822         demux->current_partition->partition.this_partition);
3823   else
3824     GST_DEBUG_OBJECT (demux, "Haven't found partition for offset yet");
3825 }
3826
3827 static guint64
3828 find_closest_offset (GArray * offsets, gint64 * position, gboolean keyframe)
3829 {
3830   GstMXFDemuxIndex *idx;
3831   gint64 current_position = *position;
3832
3833   if (!offsets || offsets->len == 0)
3834     return -1;
3835
3836   current_position = MIN (current_position, offsets->len - 1);
3837
3838   idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
3839   while (idx->offset == 0 || (keyframe && !idx->keyframe)) {
3840     current_position--;
3841     if (current_position < 0)
3842       break;
3843     idx = &g_array_index (offsets, GstMXFDemuxIndex, current_position);
3844   }
3845
3846   if (idx->offset != 0 && (!keyframe || idx->keyframe)) {
3847     *position = current_position;
3848     return idx->offset;
3849   }
3850
3851   return -1;
3852 }
3853
3854 static guint64
3855 gst_mxf_demux_find_essence_element (GstMXFDemux * demux,
3856     GstMXFDemuxEssenceTrack * etrack, gint64 * position, gboolean keyframe)
3857 {
3858   GstFlowReturn ret = GST_FLOW_OK;
3859   guint64 old_offset = demux->offset;
3860   GstMXFDemuxPartition *old_partition = demux->current_partition;
3861   gint i;
3862   guint64 offset;
3863   gint64 requested_position = *position, index_start_position;
3864   GstMXFDemuxIndex index_entry = { 0, };
3865
3866   GST_DEBUG_OBJECT (demux, "Trying to find essence element %" G_GINT64_FORMAT
3867       " of track 0x%08x with body_sid %u (keyframe %d)", *position,
3868       etrack->track_number, etrack->body_sid, keyframe);
3869
3870   /* Get entry from index table if present */
3871   if (find_edit_entry (demux, etrack, *position, keyframe, &index_entry)) {
3872     GST_DEBUG_OBJECT (demux,
3873         "Got position %" G_GINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
3874         index_entry.dts, index_entry.offset);
3875     *position = index_entry.dts;
3876     return index_entry.offset;
3877   }
3878
3879   GST_DEBUG_OBJECT (demux, "Not found in index table");
3880
3881   /* Fallback to track offsets */
3882
3883   if (!demux->random_access) {
3884     /* Best effort for push mode */
3885     offset = find_closest_offset (etrack->offsets, position, keyframe);
3886     if (offset != -1)
3887       GST_DEBUG_OBJECT (demux,
3888           "Starting with edit unit %" G_GINT64_FORMAT " for %" G_GINT64_FORMAT
3889           " in generated index at offset %" G_GUINT64_FORMAT, *position,
3890           requested_position, offset);
3891     return offset;
3892   }
3893
3894   if (etrack->duration > 0 && *position >= etrack->duration) {
3895     GST_WARNING_OBJECT (demux, "Position after end of essence track");
3896     return -1;
3897   }
3898
3899 from_track_offset:
3900
3901   index_start_position = *position;
3902
3903   demux->offset = demux->run_in;
3904
3905   offset = find_closest_offset (etrack->offsets, &index_start_position, FALSE);
3906   if (offset != -1) {
3907     demux->offset = offset + demux->run_in;
3908     GST_DEBUG_OBJECT (demux,
3909         "Starting with edit unit %" G_GINT64_FORMAT " for %" G_GINT64_FORMAT
3910         " in generated index at offset %" G_GUINT64_FORMAT,
3911         index_start_position, requested_position, offset);
3912   } else {
3913     index_start_position = -1;
3914   }
3915
3916   gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
3917
3918   for (i = 0; i < demux->essence_tracks->len; i++) {
3919     GstMXFDemuxEssenceTrack *t =
3920         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
3921
3922     if (index_start_position != -1 && t == etrack)
3923       t->position = index_start_position;
3924     else
3925       t->position = (demux->offset == demux->run_in) ? 0 : -1;
3926     GST_LOG_OBJECT (demux, "Setting track %d position to %" G_GINT64_FORMAT,
3927         t->track_id, t->position);
3928   }
3929
3930   /* Else peek at all essence elements and complete our
3931    * index until we find the requested element
3932    */
3933   while (ret == GST_FLOW_OK) {
3934     GstMXFKLV klv;
3935
3936     GST_LOG_OBJECT (demux, "Pulling from offset %" G_GINT64_FORMAT,
3937         demux->offset);
3938     ret = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
3939
3940     if (ret == GST_FLOW_EOS) {
3941       /* Handle EOS */
3942       for (i = 0; i < demux->essence_tracks->len; i++) {
3943         GstMXFDemuxEssenceTrack *t =
3944             &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
3945             i);
3946
3947         if (t->position > 0)
3948           t->duration = t->position;
3949       }
3950       /* For the searched track this is really our position */
3951       etrack->duration = etrack->position;
3952
3953       for (i = 0; i < demux->src->len; i++) {
3954         GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
3955
3956         if (!p->eos
3957             && p->current_essence_track_position >=
3958             p->current_essence_track->duration) {
3959           GstEvent *e;
3960
3961           p->eos = TRUE;
3962           e = gst_event_new_eos ();
3963           gst_event_set_seqnum (e, demux->seqnum);
3964           gst_pad_push_event (GST_PAD_CAST (p), e);
3965         }
3966       }
3967     }
3968
3969     GST_LOG_OBJECT (demux,
3970         "pulling gave flow:%s track->position:%" G_GINT64_FORMAT,
3971         gst_flow_get_name (ret), etrack->position);
3972     if (G_UNLIKELY (ret != GST_FLOW_OK) && etrack->position <= *position) {
3973       demux->offset = old_offset;
3974       demux->current_partition = old_partition;
3975       break;
3976     } else if (G_UNLIKELY (ret == GST_FLOW_OK)) {
3977       ret = gst_mxf_demux_handle_klv_packet (demux, &klv, TRUE);
3978       gst_mxf_demux_consume_klv (demux, &klv);
3979     }
3980
3981     GST_LOG_OBJECT (demux,
3982         "Handling gave flow:%s track->position:%" G_GINT64_FORMAT
3983         " looking for %" G_GINT64_FORMAT, gst_flow_get_name (ret),
3984         etrack->position, *position);
3985
3986     /* If we found the position read it from the index again */
3987     if (((ret == GST_FLOW_OK && etrack->position == *position + 1) ||
3988             (ret == GST_FLOW_EOS && etrack->position == *position + 1))
3989         && etrack->offsets && etrack->offsets->len > *position
3990         && g_array_index (etrack->offsets, GstMXFDemuxIndex,
3991             *position).offset != 0) {
3992       GST_DEBUG_OBJECT (demux, "Found at offset %" G_GUINT64_FORMAT,
3993           demux->offset);
3994       demux->offset = old_offset;
3995       demux->current_partition = old_partition;
3996       if (find_edit_entry (demux, etrack, *position, keyframe, &index_entry)) {
3997         GST_DEBUG_OBJECT (demux,
3998             "Got position %" G_GINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
3999             index_entry.dts, index_entry.offset);
4000         *position = index_entry.dts;
4001         return index_entry.offset;
4002       }
4003       goto from_track_offset;
4004     }
4005   }
4006   demux->offset = old_offset;
4007   demux->current_partition = old_partition;
4008
4009   GST_DEBUG_OBJECT (demux, "Not found in this file");
4010
4011   return -1;
4012 }
4013
4014 static GstFlowReturn
4015 gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
4016 {
4017   GstMXFKLV klv;
4018   GstFlowReturn ret = GST_FLOW_OK;
4019   gboolean force_switch = FALSE;
4020
4021   if (demux->src->len > 0) {
4022     if (!gst_mxf_demux_get_earliest_pad (demux)) {
4023       ret = GST_FLOW_EOS;
4024       GST_DEBUG_OBJECT (demux, "All tracks are EOS");
4025       goto beach;
4026     }
4027   }
4028
4029   if (demux->state == GST_MXF_DEMUX_STATE_ESSENCE) {
4030     g_assert (demux->current_partition->single_track
4031         && demux->current_partition->single_track->wrapping !=
4032         MXF_ESSENCE_WRAPPING_FRAME_WRAPPING);
4033     /* Feeding essence directly (i.e. in the middle of a custom/clip KLV) */
4034     ret =
4035         gst_mxf_demux_handle_generic_container_essence_element (demux,
4036         &demux->current_partition->clip_klv, FALSE);
4037     gst_mxf_demux_consume_klv (demux, &demux->current_partition->clip_klv);
4038     if (ret == GST_FLOW_OK
4039         && demux->current_partition->single_track->position >=
4040         demux->current_partition->single_track->duration) {
4041       /* We are done with the contents of this clip/custom wrapping, force the
4042        * switch to the next non-EOS track */
4043       GST_DEBUG_OBJECT (demux, "Single track EOS, switch");
4044       force_switch = TRUE;
4045     }
4046
4047   } else {
4048
4049     ret = gst_mxf_demux_peek_klv_packet (demux, demux->offset, &klv);
4050
4051     /* FIXME
4052      *
4053      * Move this EOS handling to a separate function
4054      */
4055     if (ret == GST_FLOW_EOS && demux->src->len > 0) {
4056       guint i;
4057       GstMXFDemuxPad *p = NULL;
4058
4059       GST_DEBUG_OBJECT (demux, "EOS HANDLING");
4060
4061       for (i = 0; i < demux->src->len; i++) {
4062         GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4063
4064         GST_DEBUG_OBJECT (p,
4065             "eos:%d current_essence_track_position:%" G_GINT64_FORMAT
4066             " position:%" G_GINT64_FORMAT " duration:%" G_GINT64_FORMAT, p->eos,
4067             p->current_essence_track_position,
4068             p->current_essence_track->position,
4069             p->current_essence_track->duration);
4070         if (!p->eos
4071             && p->current_essence_track->position >=
4072             p->current_essence_track->duration) {
4073           GstEvent *e;
4074
4075           p->eos = TRUE;
4076           e = gst_event_new_eos ();
4077           gst_event_set_seqnum (e, demux->seqnum);
4078           gst_pad_push_event (GST_PAD_CAST (p), e);
4079         }
4080       }
4081
4082       while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
4083         guint64 offset;
4084         gint64 position;
4085
4086         GST_DEBUG_OBJECT (p, "Trying on earliest");
4087
4088         position = p->current_essence_track_position;
4089
4090         offset =
4091             gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
4092             &position, FALSE);
4093         if (offset == -1) {
4094           GstEvent *e;
4095
4096           GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
4097           p->eos = TRUE;
4098           e = gst_event_new_eos ();
4099           gst_event_set_seqnum (e, demux->seqnum);
4100           gst_pad_push_event (GST_PAD_CAST (p), e);
4101           continue;
4102         }
4103
4104         demux->offset = offset + demux->run_in;
4105         gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4106         if (p->current_essence_track->wrapping !=
4107             MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4108           demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4109           demux->current_partition->clip_klv.consumed =
4110               offset - demux->current_partition->clip_klv.offset;
4111         } else
4112           demux->state = GST_MXF_DEMUX_STATE_KLV;
4113         p->current_essence_track->position = position;
4114
4115         ret = GST_FLOW_OK;
4116         goto beach;
4117       }
4118     }
4119     if (G_UNLIKELY (ret != GST_FLOW_OK))
4120       goto beach;
4121
4122     ret = gst_mxf_demux_handle_klv_packet (demux, &klv, FALSE);
4123     gst_mxf_demux_consume_klv (demux, &klv);
4124
4125     /* We entered a new partition */
4126     if (ret == GST_FLOW_OK && mxf_is_partition_pack (&klv.key)) {
4127       GstMXFDemuxPartition *partition = demux->current_partition;
4128       gboolean partition_done = FALSE;
4129
4130       /* Grab footer metadata if needed */
4131       if (demux->pull_footer_metadata
4132           && partition->partition.type == MXF_PARTITION_PACK_HEADER
4133           && (!partition->partition.closed || !partition->partition.complete)
4134           && (demux->footer_partition_pack_offset != 0
4135               || demux->random_index_pack)) {
4136         GST_DEBUG_OBJECT (demux,
4137             "Open or incomplete header partition, trying to get final metadata from the last partitions");
4138         gst_mxf_demux_parse_footer_metadata (demux);
4139         demux->pull_footer_metadata = FALSE;
4140       }
4141
4142       /* If the partition has some content, do post-checks */
4143       if (partition->partition.body_sid != 0) {
4144         guint64 lowest_offset = G_MAXUINT64;
4145         GST_DEBUG_OBJECT (demux,
4146             "Entered partition (body_sid:%d index_sid:%d body_offset:%"
4147             G_GUINT64_FORMAT "), checking positions",
4148             partition->partition.body_sid, partition->partition.index_sid,
4149             partition->partition.body_offset);
4150
4151         if (partition->single_track) {
4152           /* Fast-path for single track partition */
4153           if (partition->single_track->position == -1
4154               && partition->partition.body_offset == 0) {
4155             GST_DEBUG_OBJECT (demux,
4156                 "First time in partition, setting track position to 0");
4157             partition->single_track->position = 0;
4158           } else if (partition->single_track->position == -1) {
4159             GST_ERROR_OBJECT (demux,
4160                 "Unknown track position, consuming data from first partition entry");
4161             lowest_offset =
4162                 partition->partition.this_partition +
4163                 partition->essence_container_offset;
4164             partition->clip_klv.consumed = 0;
4165           } else if (partition->single_track->position != 0) {
4166             GstMXFDemuxIndex entry;
4167             GST_DEBUG_OBJECT (demux,
4168                 "Track already at another position : %" G_GINT64_FORMAT,
4169                 partition->single_track->position);
4170             if (find_edit_entry (demux, partition->single_track,
4171                     partition->single_track->position, FALSE, &entry)) {
4172               lowest_offset = entry.offset;
4173             } else if (partition->single_track->position >=
4174                 partition->single_track->duration) {
4175               GST_DEBUG_OBJECT (demux, "Track fully consumed, partition done");
4176               partition_done = TRUE;
4177             }
4178           }
4179         } else {
4180           guint i;
4181           for (i = 0; i < demux->essence_tracks->len; i++) {
4182             GstMXFDemuxEssenceTrack *etrack =
4183                 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
4184                 i);
4185
4186             if (etrack->body_sid != partition->partition.body_sid)
4187               continue;
4188             if (etrack->position == -1 && partition->partition.body_offset == 0) {
4189               GST_DEBUG_OBJECT (demux, "Resetting track %d to position 0",
4190                   etrack->track_id);
4191
4192               etrack->position = 0;
4193             } else if (etrack->position != 0) {
4194               GstMXFDemuxIndex entry;
4195               if (find_edit_entry (demux, etrack,
4196                       etrack->position, FALSE, &entry)) {
4197                 if (lowest_offset == G_MAXUINT64
4198                     || entry.offset < lowest_offset)
4199                   lowest_offset = entry.offset;
4200               }
4201             }
4202           }
4203         }
4204
4205         if (partition_done || lowest_offset != G_MAXUINT64) {
4206           GstMXFDemuxPartition *next_partition = NULL;
4207           GList *cur_part = g_list_find (demux->partitions, partition);
4208           if (cur_part && cur_part->next)
4209             next_partition = (GstMXFDemuxPartition *) cur_part->next->data;
4210
4211           /* If we have completely processed this partition, skip to next partition */
4212           if (partition_done
4213               || lowest_offset > next_partition->partition.this_partition) {
4214             GST_DEBUG_OBJECT (demux,
4215                 "Partition entirely processed, skipping to next one");
4216             demux->offset = next_partition->partition.this_partition;
4217           } else {
4218             GST_DEBUG_OBJECT (demux,
4219                 "Skipping to demuxer offset %" G_GUINT64_FORMAT " (from %"
4220                 G_GUINT64_FORMAT ")", lowest_offset, demux->offset);
4221             demux->offset = lowest_offset;
4222             if (partition->single_track
4223                 && partition->single_track->wrapping !=
4224                 MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4225               demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4226               demux->current_partition->clip_klv.consumed =
4227                   demux->offset - demux->current_partition->clip_klv.offset;
4228             }
4229           }
4230         }
4231       }
4232     }
4233   }
4234
4235   if (ret == GST_FLOW_OK && demux->src->len > 0
4236       && demux->essence_tracks->len > 0) {
4237     GstMXFDemuxPad *earliest = NULL;
4238     /* We allow time drifts of at most 500ms */
4239     while ((earliest = gst_mxf_demux_get_earliest_pad (demux)) && (force_switch
4240             || demux->segment.position - earliest->position >
4241             demux->max_drift)) {
4242       guint64 offset;
4243       gint64 position;
4244
4245       GST_DEBUG_OBJECT (demux,
4246           "Found synchronization issue -- trying to solve");
4247
4248       position = earliest->current_essence_track_position;
4249
4250       /* FIXME: This can probably be improved by using the
4251        * offset of position-1 if it's in the same partition
4252        * or the start of the position otherwise.
4253        * This way we won't skip elements from the same essence
4254        * container as etrack->position
4255        */
4256       offset =
4257           gst_mxf_demux_find_essence_element (demux,
4258           earliest->current_essence_track, &position, FALSE);
4259       if (offset == -1) {
4260         GstEvent *e;
4261
4262         GST_WARNING_OBJECT (demux,
4263             "Failed to find offset for late essence track");
4264         earliest->eos = TRUE;
4265         e = gst_event_new_eos ();
4266         gst_event_set_seqnum (e, demux->seqnum);
4267         gst_pad_push_event (GST_PAD_CAST (earliest), e);
4268         continue;
4269       }
4270
4271       demux->offset = offset + demux->run_in;
4272       gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4273       GST_DEBUG_OBJECT (demux,
4274           "Switching to offset %" G_GUINT64_FORMAT " for position %"
4275           G_GINT64_FORMAT " on track %d (body_sid:%d index_sid:%d)",
4276           demux->offset, position, earliest->current_essence_track->track_id,
4277           earliest->current_essence_track->body_sid,
4278           earliest->current_essence_track->index_sid);
4279       if (demux->current_partition->single_track
4280           && demux->current_partition->single_track->wrapping !=
4281           MXF_ESSENCE_WRAPPING_FRAME_WRAPPING) {
4282         demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
4283         demux->current_partition->clip_klv.consumed =
4284             offset - demux->current_partition->clip_klv.offset;
4285       } else
4286         demux->state = GST_MXF_DEMUX_STATE_KLV;
4287
4288       earliest->current_essence_track->position = position;
4289       GST_DEBUG_OBJECT (earliest, "Switching to this pad");
4290       break;
4291     }
4292   }
4293
4294 beach:
4295   return ret;
4296 }
4297
4298 static void
4299 gst_mxf_demux_loop (GstPad * pad)
4300 {
4301   GstMXFDemux *demux = NULL;
4302   GstFlowReturn flow = GST_FLOW_OK;
4303
4304   demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
4305
4306   if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4307     GstMXFKLV klv;
4308
4309     /* Skip run-in, which is at most 64K and is finished
4310      * by a header partition pack */
4311     while (demux->offset < 64 * 1024) {
4312       if ((flow =
4313               gst_mxf_demux_peek_klv_packet (demux, demux->offset,
4314                   &klv)) != GST_FLOW_OK)
4315         goto pause;
4316
4317       if (mxf_is_header_partition_pack (&klv.key)) {
4318         GST_DEBUG_OBJECT (demux,
4319             "Found header partition pack at offset %" G_GUINT64_FORMAT,
4320             demux->offset);
4321         demux->state = GST_MXF_DEMUX_STATE_KLV;
4322         demux->run_in = demux->offset;
4323         break;
4324       }
4325       demux->offset++;
4326     }
4327
4328     if (G_UNLIKELY (demux->run_in == -1)) {
4329       GST_ERROR_OBJECT (demux, "No valid header partition pack found");
4330       flow = GST_FLOW_ERROR;
4331       goto pause;
4332     }
4333
4334     /* Grab the RIP at the end of the file (if present) */
4335     gst_mxf_demux_pull_random_index_pack (demux);
4336   }
4337
4338   /* Now actually do something */
4339   flow = gst_mxf_demux_pull_and_handle_klv_packet (demux);
4340
4341   /* pause if something went wrong */
4342   if (G_UNLIKELY (flow != GST_FLOW_OK))
4343     goto pause;
4344
4345   /* check EOS condition */
4346   if ((demux->segment.stop != -1) &&
4347       (demux->segment.position >= demux->segment.stop)) {
4348     guint i;
4349     gboolean eos = TRUE;
4350
4351     for (i = 0; i < demux->src->len; i++) {
4352       GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4353
4354       if (!p->eos && p->position < demux->segment.stop) {
4355         eos = FALSE;
4356         break;
4357       }
4358     }
4359
4360     if (eos) {
4361       flow = GST_FLOW_EOS;
4362       goto pause;
4363     }
4364   }
4365
4366   gst_object_unref (demux);
4367
4368   return;
4369
4370 pause:
4371   {
4372     const gchar *reason = gst_flow_get_name (flow);
4373
4374     GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
4375     gst_pad_pause_task (pad);
4376
4377     if (flow == GST_FLOW_EOS) {
4378       /* perform EOS logic */
4379       if (demux->src->len == 0) {
4380         GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
4381             ("This stream contains no data."),
4382             ("got eos and didn't find any streams"));
4383       } else if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4384         gint64 stop;
4385         GstMessage *m;
4386         GstEvent *e;
4387
4388         /* for segment playback we need to post when (in stream time)
4389          * we stopped, this is either stop (when set) or the duration. */
4390         if ((stop = demux->segment.stop) == -1)
4391           stop = demux->segment.duration;
4392
4393         GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
4394         m = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
4395             GST_FORMAT_TIME, stop);
4396         gst_message_set_seqnum (m, demux->seqnum);
4397         gst_element_post_message (GST_ELEMENT_CAST (demux), m);
4398         e = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
4399         gst_event_set_seqnum (e, demux->seqnum);
4400         gst_mxf_demux_push_src_event (demux, e);
4401       } else {
4402         GstEvent *e;
4403
4404         /* normal playback, send EOS to all linked pads */
4405         GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
4406         e = gst_event_new_eos ();
4407         gst_event_set_seqnum (e, demux->seqnum);
4408         if (!gst_mxf_demux_push_src_event (demux, e)) {
4409           GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
4410         }
4411       }
4412     } else if (flow == GST_FLOW_NOT_LINKED || flow < GST_FLOW_EOS) {
4413       GstEvent *e;
4414
4415       GST_ELEMENT_FLOW_ERROR (demux, flow);
4416       e = gst_event_new_eos ();
4417       gst_event_set_seqnum (e, demux->seqnum);
4418       gst_mxf_demux_push_src_event (demux, e);
4419     }
4420     gst_object_unref (demux);
4421     return;
4422   }
4423 }
4424
4425 static GstFlowReturn
4426 gst_mxf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
4427 {
4428   GstFlowReturn ret = GST_FLOW_OK;
4429   GstMXFDemux *demux = NULL;
4430   const guint8 *data = NULL;
4431   gboolean res;
4432   GstMXFKLV klv;
4433 #ifndef GST_DISABLE_GST_DEBUG
4434   gchar str[48];
4435 #endif
4436
4437   demux = GST_MXF_DEMUX (parent);
4438
4439   GST_LOG_OBJECT (demux,
4440       "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
4441       G_GUINT64_FORMAT, gst_buffer_get_size (inbuf), GST_BUFFER_OFFSET (inbuf));
4442
4443   if (demux->src->len > 0) {
4444     if (!gst_mxf_demux_get_earliest_pad (demux)) {
4445       ret = GST_FLOW_EOS;
4446       GST_DEBUG_OBJECT (demux, "All tracks are EOS");
4447       return ret;
4448     }
4449   }
4450
4451   if (G_UNLIKELY (GST_BUFFER_OFFSET (inbuf) == 0)) {
4452     GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
4453     demux->run_in = -1;
4454     demux->offset = 0;
4455     demux->state = GST_MXF_DEMUX_STATE_UNKNOWN;
4456   }
4457
4458   if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (inbuf) != 0)) {
4459     GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
4460     if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
4461       demux->offset = GST_BUFFER_OFFSET (inbuf);
4462     gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4463   } else if (demux->current_partition == NULL) {
4464     gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
4465   }
4466
4467   gst_adapter_push (demux->adapter, inbuf);
4468   inbuf = NULL;
4469
4470   while (ret == GST_FLOW_OK) {
4471     if (G_UNLIKELY (demux->flushing)) {
4472       GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
4473       ret = GST_FLOW_FLUSHING;
4474       break;
4475     }
4476
4477     if (gst_adapter_available (demux->adapter) < 16)
4478       break;
4479
4480     if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4481       /* Skip run-in, which is at most 64K and is finished
4482        * by a header partition pack */
4483
4484       while (demux->offset < 64 * 1024
4485           && gst_adapter_available (demux->adapter) >= 16) {
4486         data = gst_adapter_map (demux->adapter, 16);
4487         res = mxf_is_header_partition_pack ((const MXFUL *) data);
4488         gst_adapter_unmap (demux->adapter);
4489
4490         if (res) {
4491           GST_DEBUG_OBJECT (demux,
4492               "Found header partition pack at offset %" G_GUINT64_FORMAT,
4493               demux->offset);
4494           demux->run_in = demux->offset;
4495           demux->state = GST_MXF_DEMUX_STATE_KLV;
4496           break;
4497         }
4498         gst_adapter_flush (demux->adapter, 1);
4499         demux->offset++;
4500       }
4501     } else if (demux->offset < demux->run_in) {
4502       guint64 flush = MIN (gst_adapter_available (demux->adapter),
4503           demux->run_in - demux->offset);
4504       gst_adapter_flush (demux->adapter, flush);
4505       demux->offset += flush;
4506       continue;
4507     }
4508
4509     if (demux->state == GST_MXF_DEMUX_STATE_UNKNOWN) {
4510       /* Need more data */
4511       if (demux->offset < 64 * 1024)
4512         break;
4513
4514       GST_ERROR_OBJECT (demux, "No valid header partition pack found");
4515       ret = GST_FLOW_ERROR;
4516       break;
4517     }
4518
4519     if (gst_adapter_available (demux->adapter) < 17)
4520       break;
4521
4522     /* FIXME : Handle non-klv state */
4523     g_assert (demux->state == GST_MXF_DEMUX_STATE_KLV);
4524
4525     /* Now actually do something */
4526     memset (&klv, 0, sizeof (GstMXFKLV));
4527
4528     /* Pull 16 byte key and first byte of BER encoded length */
4529     data = gst_adapter_map (demux->adapter, 17);
4530
4531     memcpy (&klv.key, data, 16);
4532
4533     GST_DEBUG_OBJECT (demux, "Got KLV packet with key %s",
4534         mxf_ul_to_string (&klv.key, str));
4535
4536     /* Decode BER encoded packet length */
4537     if ((data[16] & 0x80) == 0) {
4538       klv.length = data[16];
4539       klv.data_offset = 17;
4540     } else {
4541       guint slen = data[16] & 0x7f;
4542
4543       klv.data_offset = 16 + 1 + slen;
4544
4545       gst_adapter_unmap (demux->adapter);
4546
4547       /* Must be at most 8 according to SMPTE-379M 5.3.4 and
4548        * GStreamer buffers can only have a 4 bytes length */
4549       if (slen > 8) {
4550         GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %u", slen);
4551         ret = GST_FLOW_ERROR;
4552         break;
4553       }
4554
4555       if (gst_adapter_available (demux->adapter) < 17 + slen)
4556         break;
4557
4558       data = gst_adapter_map (demux->adapter, 17 + slen);
4559       data += 17;
4560
4561       klv.length = 0;
4562       while (slen) {
4563         klv.length = (klv.length << 8) | *data;
4564         data++;
4565         slen--;
4566       }
4567     }
4568
4569     gst_adapter_unmap (demux->adapter);
4570
4571     /* GStreamer's buffer sizes are stored in a guint so we
4572      * limit ourself to G_MAXUINT large buffers */
4573     if (klv.length > G_MAXUINT) {
4574       GST_ERROR_OBJECT (demux,
4575           "Unsupported KLV packet length: %" G_GSIZE_FORMAT, klv.length);
4576       ret = GST_FLOW_ERROR;
4577       break;
4578     }
4579
4580     GST_DEBUG_OBJECT (demux, "KLV packet with key %s has length "
4581         "%" G_GSIZE_FORMAT, mxf_ul_to_string (&klv.key, str), klv.length);
4582
4583     if (gst_adapter_available (demux->adapter) < klv.data_offset + klv.length)
4584       break;
4585
4586     gst_adapter_flush (demux->adapter, klv.data_offset);
4587
4588     if (klv.length > 0) {
4589       klv.data = gst_adapter_take_buffer (demux->adapter, klv.length);
4590
4591       ret = gst_mxf_demux_handle_klv_packet (demux, &klv, FALSE);
4592     }
4593     gst_mxf_demux_consume_klv (demux, &klv);
4594   }
4595
4596   return ret;
4597 }
4598
4599 /* Given a stream time for an output pad, figure out:
4600  * * The Essence track for that stream time
4601  * * The position on that track
4602  */
4603 static gboolean
4604 gst_mxf_demux_pad_to_track_and_position (GstMXFDemux * demux,
4605     GstMXFDemuxPad * pad, GstClockTime streamtime,
4606     GstMXFDemuxEssenceTrack ** etrack, gint64 * position)
4607 {
4608   gint64 material_position;
4609   guint64 sum = 0;
4610   guint i;
4611   MXFMetadataSourceClip *clip = NULL;
4612   gchar str[96];
4613
4614   /* Convert to material position */
4615   material_position =
4616       gst_util_uint64_scale (streamtime, pad->material_track->edit_rate.n,
4617       pad->material_track->edit_rate.d * GST_SECOND);
4618
4619   GST_DEBUG_OBJECT (pad,
4620       "streamtime %" GST_TIME_FORMAT " position %" G_GINT64_FORMAT,
4621       GST_TIME_ARGS (streamtime), material_position);
4622
4623
4624   /* Find sequence component covering that position */
4625   for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
4626       i++) {
4627     clip =
4628         MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
4629         structural_components[i]);
4630     GST_LOG_OBJECT (pad,
4631         "clip %d start_position:%" G_GINT64_FORMAT " duration %"
4632         G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
4633         clip->parent.duration);
4634     if (clip->parent.duration <= 0)
4635       break;
4636     if ((sum + clip->parent.duration) > material_position)
4637       break;
4638     sum += clip->parent.duration;
4639   }
4640
4641   if (i == pad->material_track->parent.sequence->n_structural_components) {
4642     GST_WARNING_OBJECT (pad, "Requested position beyond the last clip");
4643     /* Outside of current components. Setting to the end of the last clip */
4644     material_position = sum;
4645     sum -= clip->parent.duration;
4646   }
4647
4648   GST_DEBUG_OBJECT (pad, "Looking for essence track for track_id:%d umid:%s",
4649       clip->source_track_id, mxf_umid_to_string (&clip->source_package_id,
4650           str));
4651
4652   /* Get the corresponding essence track for the given source package and stream id */
4653   for (i = 0; i < demux->essence_tracks->len; i++) {
4654     GstMXFDemuxEssenceTrack *track =
4655         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
4656     GST_LOG_OBJECT (pad,
4657         "Looking at essence track body_sid:%d index_sid:%d",
4658         track->body_sid, track->index_sid);
4659     if (clip->source_track_id == 0 || (track->track_id == clip->source_track_id
4660             && mxf_umid_is_equal (&clip->source_package_id,
4661                 &track->source_package_uid))) {
4662       GST_DEBUG_OBJECT (pad,
4663           "Found matching essence track body_sid:%d index_sid:%d",
4664           track->body_sid, track->index_sid);
4665       *etrack = track;
4666       *position = material_position - sum;
4667       return TRUE;
4668     }
4669   }
4670
4671   return FALSE;
4672 }
4673
4674 /* Given a track+position for a given pad, figure out the resulting stream time */
4675 static gboolean
4676 gst_mxf_demux_pad_get_stream_time (GstMXFDemux * demux,
4677     GstMXFDemuxPad * pad, GstMXFDemuxEssenceTrack * etrack,
4678     gint64 position, GstClockTime * stream_time)
4679 {
4680   guint i;
4681   guint64 sum = 0;
4682   MXFMetadataSourceClip *clip = NULL;
4683
4684   /* Find the component for that */
4685   /* Find sequence component covering that position */
4686   for (i = 0; i < pad->material_track->parent.sequence->n_structural_components;
4687       i++) {
4688     clip =
4689         MXF_METADATA_SOURCE_CLIP (pad->material_track->parent.sequence->
4690         structural_components[i]);
4691     GST_LOG_OBJECT (pad,
4692         "clip %d start_position:%" G_GINT64_FORMAT " duration %"
4693         G_GINT64_FORMAT, clip->source_track_id, clip->start_position,
4694         clip->parent.duration);
4695     if (etrack->track_id == clip->source_track_id
4696         && mxf_umid_is_equal (&clip->source_package_id,
4697             &etrack->source_package_uid)) {
4698       /* This is the clip */
4699       break;
4700     }
4701     /* Fetch in the next one */
4702     sum += clip->parent.duration;
4703   }
4704
4705   /* Theoretically impossible */
4706   if (i == pad->material_track->parent.sequence->n_structural_components) {
4707     /* Outside of current components ?? */
4708     return FALSE;
4709   }
4710
4711   *stream_time =
4712       gst_util_uint64_scale (position + sum,
4713       pad->material_track->edit_rate.d * GST_SECOND,
4714       pad->material_track->edit_rate.n);
4715
4716   return TRUE;
4717 }
4718
4719 static void
4720 gst_mxf_demux_pad_set_position (GstMXFDemux * demux, GstMXFDemuxPad * p,
4721     GstClockTime start)
4722 {
4723   guint i;
4724   guint64 sum = 0;
4725   MXFMetadataSourceClip *clip = NULL;
4726
4727   if (!p->current_component) {
4728     p->current_essence_track_position =
4729         gst_util_uint64_scale (start, p->material_track->edit_rate.n,
4730         p->material_track->edit_rate.d * GST_SECOND);
4731
4732     if (p->current_essence_track_position >= p->current_essence_track->duration
4733         && p->current_essence_track->duration > 0) {
4734       p->current_essence_track_position = p->current_essence_track->duration;
4735       p->position =
4736           gst_util_uint64_scale (p->current_essence_track->duration,
4737           p->material_track->edit_rate.d * GST_SECOND,
4738           p->material_track->edit_rate.n);
4739     } else {
4740       p->position = start;
4741     }
4742     p->position_accumulated_error = 0.0;
4743     p->current_material_track_position = p->current_essence_track_position;
4744
4745     return;
4746   }
4747
4748   for (i = 0; i < p->material_track->parent.sequence->n_structural_components;
4749       i++) {
4750     clip =
4751         MXF_METADATA_SOURCE_CLIP (p->material_track->parent.sequence->
4752         structural_components[i]);
4753
4754     if (clip->parent.duration <= 0)
4755       break;
4756
4757     sum += clip->parent.duration;
4758
4759     if (gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4760             p->material_track->edit_rate.n) > start)
4761       break;
4762   }
4763
4764   if (i == p->material_track->parent.sequence->n_structural_components) {
4765     p->position =
4766         gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4767         p->material_track->edit_rate.n);
4768     p->position_accumulated_error = 0.0;
4769     p->current_material_track_position = sum;
4770
4771     gst_mxf_demux_pad_set_component (demux, p, i);
4772     return;
4773   }
4774
4775   if (clip->parent.duration > 0)
4776     sum -= clip->parent.duration;
4777
4778   start -=
4779       gst_util_uint64_scale (sum, p->material_track->edit_rate.d * GST_SECOND,
4780       p->material_track->edit_rate.n);
4781
4782   gst_mxf_demux_pad_set_component (demux, p, i);
4783
4784   {
4785     gint64 essence_offset = gst_util_uint64_scale (start,
4786         p->current_essence_track->source_track->edit_rate.n,
4787         p->current_essence_track->source_track->edit_rate.d * GST_SECOND);
4788
4789     p->current_essence_track_position += essence_offset;
4790
4791     p->position = gst_util_uint64_scale (sum,
4792         GST_SECOND * p->material_track->edit_rate.d,
4793         p->material_track->edit_rate.n) + gst_util_uint64_scale (essence_offset,
4794         GST_SECOND * p->current_essence_track->source_track->edit_rate.d,
4795         p->current_essence_track->source_track->edit_rate.n);
4796     p->position_accumulated_error = 0.0;
4797     p->current_material_track_position = sum + essence_offset;
4798   }
4799
4800   if (p->current_essence_track_position >= p->current_essence_track->duration
4801       && p->current_essence_track->duration > 0) {
4802     p->current_essence_track_position = p->current_essence_track->duration;
4803     p->position =
4804         gst_util_uint64_scale (sum + p->current_component->parent.duration,
4805         p->material_track->edit_rate.d * GST_SECOND,
4806         p->material_track->edit_rate.n);
4807     p->position_accumulated_error = 0.0;
4808     p->current_material_track_position =
4809         sum + p->current_component->parent.duration;
4810   }
4811 }
4812
4813 static gboolean
4814 gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event)
4815 {
4816   GstFormat format;
4817   GstSeekFlags flags;
4818   GstSeekType start_type, stop_type;
4819   gint64 start, stop;
4820   gdouble rate;
4821   gboolean update, flush, keyframe;
4822   GstSegment seeksegment;
4823   guint i;
4824   guint32 seqnum;
4825
4826   gst_event_parse_seek (event, &rate, &format, &flags,
4827       &start_type, &start, &stop_type, &stop);
4828   seqnum = gst_event_get_seqnum (event);
4829
4830   if (rate <= 0.0)
4831     goto wrong_rate;
4832
4833   if (format != GST_FORMAT_TIME)
4834     goto wrong_format;
4835
4836   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
4837   keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
4838
4839   /* Work on a copy until we are sure the seek succeeded. */
4840   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
4841
4842   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
4843       &demux->segment);
4844
4845   /* Apply the seek to our segment */
4846   gst_segment_do_seek (&seeksegment, rate, format, flags,
4847       start_type, start, stop_type, stop, &update);
4848
4849   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
4850       &seeksegment);
4851
4852   if (flush || seeksegment.position != demux->segment.position) {
4853     gboolean ret;
4854     guint64 new_offset = -1;
4855     GstEvent *e;
4856
4857     if (!demux->metadata_resolved || demux->update_metadata) {
4858       if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
4859           gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
4860         goto unresolved_metadata;
4861       }
4862     }
4863
4864     /* Do the actual seeking */
4865     for (i = 0; i < demux->src->len; i++) {
4866       GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4867       gint64 position;
4868       guint64 off;
4869
4870       /* Reset EOS flag on all pads */
4871       p->eos = FALSE;
4872       gst_mxf_demux_pad_set_position (demux, p, start);
4873
4874       position = p->current_essence_track_position;
4875       off = gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
4876           &position, keyframe);
4877       new_offset = MIN (off, new_offset);
4878       p->discont = TRUE;
4879     }
4880
4881     if (new_offset == -1)
4882       goto no_new_offset;
4883
4884     new_offset += demux->run_in;
4885
4886     GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
4887         G_GUINT64_FORMAT, new_offset);
4888     e = gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
4889         seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
4890         new_offset, GST_SEEK_TYPE_NONE, 0);
4891     gst_event_set_seqnum (e, seqnum);
4892     ret = gst_pad_push_event (demux->sinkpad, e);
4893
4894     if (G_UNLIKELY (!ret)) {
4895       goto seek_failed;
4896     }
4897   }
4898
4899   /* Tell all the stream a new segment is needed */
4900   for (i = 0; i < demux->src->len; i++) {
4901     GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
4902     p->need_segment = TRUE;
4903   }
4904
4905   for (i = 0; i < demux->essence_tracks->len; i++) {
4906     GstMXFDemuxEssenceTrack *t =
4907         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
4908     t->position = -1;
4909   }
4910
4911   /* Ok seek succeeded, take the newly configured segment */
4912   memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
4913
4914   return TRUE;
4915
4916 /* ERRORS */
4917 wrong_format:
4918   {
4919     GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
4920     return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4921   }
4922 wrong_rate:
4923   {
4924     GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
4925     return FALSE;
4926   }
4927 unresolved_metadata:
4928   {
4929     GST_WARNING_OBJECT (demux, "metadata can't be resolved");
4930     return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4931   }
4932 seek_failed:
4933   {
4934     GST_WARNING_OBJECT (demux, "upstream seek failed");
4935     return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4936   }
4937 no_new_offset:
4938   {
4939     GST_WARNING_OBJECT (demux, "can't find new offset");
4940     return gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
4941   }
4942 }
4943
4944 static void
4945 collect_index_table_segments (GstMXFDemux * demux)
4946 {
4947   GList *l;
4948   guint i;
4949   guint64 old_offset = demux->offset;
4950   GstMXFDemuxPartition *old_partition = demux->current_partition;
4951
4952   /* This function can also be called when a RIP is not present. This can happen
4953    * if index table segments were discovered while scanning the file */
4954   if (demux->random_index_pack) {
4955     for (i = 0; i < demux->random_index_pack->len; i++) {
4956       MXFRandomIndexPackEntry *e =
4957           &g_array_index (demux->random_index_pack, MXFRandomIndexPackEntry, i);
4958
4959       if (e->offset < demux->run_in) {
4960         GST_ERROR_OBJECT (demux, "Invalid random index pack entry");
4961         return;
4962       }
4963
4964       demux->offset = e->offset;
4965       read_partition_header (demux);
4966     }
4967
4968     demux->offset = old_offset;
4969     demux->current_partition = old_partition;
4970   }
4971
4972   if (demux->pending_index_table_segments == NULL) {
4973     GST_DEBUG_OBJECT (demux, "No pending index table segments to collect");
4974     return;
4975   }
4976
4977   GST_LOG_OBJECT (demux, "Collecting pending index table segments");
4978
4979   for (l = demux->pending_index_table_segments; l; l = l->next) {
4980     MXFIndexTableSegment *segment = l->data;
4981     GstMXFDemuxIndexTable *t = NULL;
4982     GList *k;
4983     guint didx;
4984 #ifndef GST_DISABLE_GST_DEBUG
4985     gchar str[48];
4986 #endif
4987
4988     GST_LOG_OBJECT (demux,
4989         "Collecting from segment bodySID:%d indexSID:%d instance_id: %s",
4990         segment->body_sid, segment->index_sid,
4991         mxf_uuid_to_string (&segment->instance_id, str));
4992
4993     for (k = demux->index_tables; k; k = k->next) {
4994       GstMXFDemuxIndexTable *tmp = k->data;
4995
4996       if (tmp->body_sid == segment->body_sid
4997           && tmp->index_sid == segment->index_sid) {
4998         t = tmp;
4999         break;
5000       }
5001     }
5002
5003     if (!t) {
5004       t = g_new0 (GstMXFDemuxIndexTable, 1);
5005       t->body_sid = segment->body_sid;
5006       t->index_sid = segment->index_sid;
5007       t->max_temporal_offset = 0;
5008       t->segments = g_array_new (FALSE, TRUE, sizeof (MXFIndexTableSegment));
5009       g_array_set_clear_func (t->segments,
5010           (GDestroyNotify) mxf_index_table_segment_reset);
5011       t->reordered_delta_entry = -1;
5012       t->reverse_temporal_offsets = g_array_new (FALSE, TRUE, 1);
5013       demux->index_tables = g_list_prepend (demux->index_tables, t);
5014     }
5015
5016     /* Store index segment */
5017     g_array_append_val (t->segments, *segment);
5018
5019     /* Check if temporal reordering tables should be pre-calculated */
5020     for (didx = 0; didx < segment->n_delta_entries; didx++) {
5021       MXFDeltaEntry *delta = &segment->delta_entries[didx];
5022       if (delta->pos_table_index == -1) {
5023         if (t->reordered_delta_entry != -1 && didx != t->reordered_delta_entry)
5024           GST_WARNING_OBJECT (demux,
5025               "Index Table specifies more than one stream using temporal reordering (%d and %d)",
5026               didx, t->reordered_delta_entry);
5027         else
5028           t->reordered_delta_entry = didx;
5029       } else if (delta->pos_table_index > 0)
5030         GST_WARNING_OBJECT (delta,
5031             "Index Table uses fractional offset, please file a bug");
5032     }
5033
5034   }
5035
5036   /* Handle temporal offset if present and needed */
5037   for (l = demux->index_tables; l; l = l->next) {
5038     GstMXFDemuxIndexTable *table = l->data;
5039     guint segidx;
5040
5041     /* No reordered entries, skip */
5042     if (table->reordered_delta_entry == -1)
5043       continue;
5044
5045     GST_DEBUG_OBJECT (demux,
5046         "bodySID:%d indexSID:%d Calculating reverse temporal offset table",
5047         table->body_sid, table->index_sid);
5048
5049     for (segidx = 0; segidx < table->segments->len; segidx++) {
5050       MXFIndexTableSegment *s =
5051           &g_array_index (table->segments, MXFIndexTableSegment, segidx);
5052       guint start = s->index_start_position;
5053       guint stop =
5054           s->index_duration ? start + s->index_duration : start +
5055           s->n_index_entries;
5056       guint entidx = 0;
5057
5058       if (stop > table->reverse_temporal_offsets->len)
5059         g_array_set_size (table->reverse_temporal_offsets, stop);
5060
5061       for (entidx = 0; entidx < s->n_index_entries; entidx++) {
5062         MXFIndexEntry *entry = &s->index_entries[entidx];
5063         gint8 offs = -entry->temporal_offset;
5064         /* Check we don't exceed boundaries */
5065         if ((start + entidx + entry->temporal_offset) < 0 ||
5066             (start + entidx + entry->temporal_offset) >
5067             table->reverse_temporal_offsets->len) {
5068           GST_ERROR_OBJECT (demux,
5069               "Temporal offset exceeds boundaries. entry:%d offset:%d max:%d",
5070               start + entidx, entry->temporal_offset,
5071               table->reverse_temporal_offsets->len);
5072         } else {
5073           /* Applying the temporal offset gives us the entry that should contain this PTS.
5074            * We store the reverse temporal offset on that entry, i.e. the value it should apply
5075            * to go from DTS to PTS. (i.e. entry.pts = entry.dts + rto[idx]) */
5076           g_array_index (table->reverse_temporal_offsets, gint8,
5077               start + entidx + entry->temporal_offset) = offs;
5078           if (entry->temporal_offset > (gint) table->max_temporal_offset) {
5079             GST_LOG_OBJECT (demux,
5080                 "Updating max temporal offset to %d (was %d)",
5081                 entry->temporal_offset, table->max_temporal_offset);
5082             table->max_temporal_offset = entry->temporal_offset;
5083           }
5084         }
5085       }
5086     }
5087   }
5088
5089   g_list_free_full (demux->pending_index_table_segments, g_free);
5090   demux->pending_index_table_segments = NULL;
5091
5092   GST_DEBUG_OBJECT (demux, "Done collecting segments");
5093 }
5094
5095 static gboolean
5096 gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
5097 {
5098   GstClockTime keyunit_ts;
5099   GstFormat format;
5100   GstSeekFlags flags;
5101   GstSeekType start_type, stop_type;
5102   gint64 start, stop;
5103   gdouble rate;
5104   gboolean update, flush, keyframe;
5105   GstSegment seeksegment;
5106   guint i;
5107   gboolean ret = TRUE;
5108   guint32 seqnum;
5109
5110   gst_event_parse_seek (event, &rate, &format, &flags,
5111       &start_type, &start, &stop_type, &stop);
5112   seqnum = gst_event_get_seqnum (event);
5113
5114   if (seqnum == demux->seqnum) {
5115     GST_DEBUG_OBJECT (demux, "Already handled requested seek");
5116     return TRUE;
5117   }
5118
5119   GST_DEBUG_OBJECT (demux, "Seek %" GST_PTR_FORMAT, event);
5120
5121   if (format != GST_FORMAT_TIME)
5122     goto wrong_format;
5123
5124   if (rate <= 0.0)
5125     goto wrong_rate;
5126
5127   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
5128   keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
5129
5130   if (!demux->index_table_segments_collected) {
5131     collect_index_table_segments (demux);
5132     demux->index_table_segments_collected = TRUE;
5133   }
5134
5135   if (flush) {
5136     GstEvent *e;
5137
5138     /* Flush start up and downstream to make sure data flow and loops are
5139        idle */
5140     e = gst_event_new_flush_start ();
5141     gst_event_set_seqnum (e, seqnum);
5142     gst_mxf_demux_push_src_event (demux, gst_event_ref (e));
5143     gst_pad_push_event (demux->sinkpad, e);
5144   } else {
5145     /* Pause the pulling task */
5146     gst_pad_pause_task (demux->sinkpad);
5147   }
5148
5149   /* Take the stream lock */
5150   GST_PAD_STREAM_LOCK (demux->sinkpad);
5151
5152   if (flush) {
5153     GstEvent *e;
5154
5155     /* Stop flushing upstream we need to pull */
5156     e = gst_event_new_flush_stop (TRUE);
5157     gst_event_set_seqnum (e, seqnum);
5158     gst_pad_push_event (demux->sinkpad, e);
5159   }
5160
5161   /* Work on a copy until we are sure the seek succeeded. */
5162   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
5163
5164   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
5165       &demux->segment);
5166
5167   /* Apply the seek to our segment */
5168   gst_segment_do_seek (&seeksegment, rate, format, flags,
5169       start_type, start, stop_type, stop, &update);
5170
5171   GST_DEBUG_OBJECT (demux,
5172       "segment initially configured to %" GST_SEGMENT_FORMAT, &seeksegment);
5173
5174   /* Initialize and reset ourselves if needed */
5175   if (flush || seeksegment.position != demux->segment.position) {
5176     GList *tmp;
5177     if (!demux->metadata_resolved || demux->update_metadata) {
5178       if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
5179           gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
5180         goto unresolved_metadata;
5181       }
5182     }
5183
5184     /* Reset all single-track KLV tracking */
5185     for (tmp = demux->partitions; tmp; tmp = tmp->next) {
5186       GstMXFDemuxPartition *partition = (GstMXFDemuxPartition *) tmp->data;
5187       if (partition->single_track) {
5188         partition->clip_klv.consumed = 0;
5189       }
5190     }
5191   }
5192
5193   keyunit_ts = seeksegment.position;
5194
5195   /* Do a first round without changing positions. This is needed to figure out
5196    * the supporting keyframe position (if any) */
5197   for (i = 0; i < demux->src->len; i++) {
5198     GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5199     GstMXFDemuxEssenceTrack *etrack;
5200     gint64 track_pos, seeked_pos;
5201
5202     /* Get track and track position for requested time, handles out of bound internally */
5203     if (!gst_mxf_demux_pad_to_track_and_position (demux, p,
5204             seeksegment.position, &etrack, &track_pos))
5205       goto invalid_position;
5206
5207     GST_LOG_OBJECT (p,
5208         "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT,
5209         etrack->track_id, etrack->body_sid, etrack->index_sid, track_pos);
5210
5211     /* Find supporting keyframe entry */
5212     seeked_pos = track_pos;
5213     if (gst_mxf_demux_find_essence_element (demux, etrack, &seeked_pos,
5214             TRUE) == -1) {
5215       /* Couldn't find entry, ignore */
5216       break;
5217     }
5218
5219     GST_LOG_OBJECT (p,
5220         "track %d (body_sid:%d index_sid:%d), position %" G_GINT64_FORMAT
5221         " entry position %" G_GINT64_FORMAT, etrack->track_id, etrack->body_sid,
5222         etrack->index_sid, track_pos, seeked_pos);
5223
5224     if (seeked_pos != track_pos) {
5225       GstClockTime stream_time;
5226       if (!gst_mxf_demux_pad_get_stream_time (demux, p, etrack, seeked_pos,
5227               &stream_time))
5228         goto invalid_position;
5229       GST_LOG_OBJECT (p, "Need to seek to stream time %" GST_TIME_FORMAT,
5230           GST_TIME_ARGS (stream_time));
5231       keyunit_ts = MIN (seeksegment.position, stream_time);
5232     }
5233   }
5234
5235   if (keyframe && keyunit_ts != seeksegment.position) {
5236     GST_INFO_OBJECT (demux, "key unit seek, adjusting segment start to "
5237         "%" GST_TIME_FORMAT, GST_TIME_ARGS (keyunit_ts));
5238     gst_segment_do_seek (&seeksegment, rate, format, flags,
5239         start_type, keyunit_ts, stop_type, stop, &update);
5240   }
5241
5242   /* Finally set the position to the calculated position */
5243   if (flush || keyunit_ts != demux->segment.position) {
5244     guint64 new_offset = -1;
5245
5246     /* Do the actual seeking */
5247     for (i = 0; i < demux->src->len; i++) {
5248       GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5249       gint64 position;
5250       guint64 off;
5251
5252       /* Reset EOS flag on all pads */
5253       p->eos = FALSE;
5254       gst_mxf_demux_pad_set_position (demux, p, seeksegment.position);
5255
5256       /* we always want to send data starting with a key unit */
5257       position = p->current_essence_track_position;
5258       off =
5259           gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
5260           &position, TRUE);
5261       if (off == -1) {
5262         GST_DEBUG_OBJECT (demux, "Unable to find offset for pad %s",
5263             GST_PAD_NAME (p));
5264         p->current_essence_track_position = p->current_essence_track->duration;
5265       } else {
5266         new_offset = MIN (off, new_offset);
5267         if (position != p->current_essence_track_position) {
5268           p->position -=
5269               gst_util_uint64_scale (p->current_essence_track_position -
5270               position,
5271               GST_SECOND * p->current_essence_track->source_track->edit_rate.d,
5272               p->current_essence_track->source_track->edit_rate.n);
5273           p->position_accumulated_error = 0.0;
5274           p->current_material_track_position -=
5275               gst_util_uint64_scale (p->current_essence_track_position -
5276               position,
5277               p->material_track->edit_rate.n *
5278               p->current_essence_track->source_track->edit_rate.d,
5279               p->material_track->edit_rate.d *
5280               p->current_essence_track->source_track->edit_rate.n);
5281         }
5282         p->current_essence_track_position = position;
5283       }
5284       p->current_essence_track->position = p->current_essence_track_position;
5285       p->discont = TRUE;
5286     }
5287     gst_flow_combiner_reset (demux->flowcombiner);
5288     if (new_offset == -1) {
5289       GST_WARNING_OBJECT (demux, "No new offset found");
5290       ret = FALSE;
5291     } else {
5292       demux->offset = new_offset + demux->run_in;
5293     }
5294     gst_mxf_demux_set_partition_for_offset (demux, demux->offset);
5295     /* Reset the state accordingly */
5296     if (demux->current_partition->single_track
5297         && demux->current_partition->single_track->wrapping !=
5298         MXF_ESSENCE_WRAPPING_FRAME_WRAPPING)
5299       demux->state = GST_MXF_DEMUX_STATE_ESSENCE;
5300     else
5301       demux->state = GST_MXF_DEMUX_STATE_KLV;
5302   }
5303
5304   if (G_UNLIKELY (demux->close_seg_event)) {
5305     gst_event_unref (demux->close_seg_event);
5306     demux->close_seg_event = NULL;
5307   }
5308
5309   if (flush) {
5310     GstEvent *e;
5311
5312     /* Stop flushing, the sinks are at time 0 now */
5313     e = gst_event_new_flush_stop (TRUE);
5314     gst_event_set_seqnum (e, seqnum);
5315     gst_mxf_demux_push_src_event (demux, e);
5316   } else {
5317     GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
5318         &demux->segment);
5319
5320     /* Close the current segment for a linear playback */
5321     demux->close_seg_event = gst_event_new_segment (&demux->segment);
5322     gst_event_set_seqnum (demux->close_seg_event, demux->seqnum);
5323   }
5324
5325   /* Ok seek succeeded, take the newly configured segment */
5326   memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
5327
5328   /* Notify about the start of a new segment */
5329   if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5330     GstMessage *m;
5331
5332     m = gst_message_new_segment_start (GST_OBJECT (demux),
5333         demux->segment.format, demux->segment.position);
5334     gst_message_set_seqnum (m, seqnum);
5335     gst_element_post_message (GST_ELEMENT (demux), m);
5336   }
5337
5338   /* Tell all the stream a new segment is needed */
5339   for (i = 0; i < demux->src->len; i++) {
5340     GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5341     p->need_segment = TRUE;
5342   }
5343
5344   for (i = 0; i < demux->essence_tracks->len; i++) {
5345     GstMXFDemuxEssenceTrack *t =
5346         &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
5347     t->position = -1;
5348   }
5349
5350   demux->seqnum = seqnum;
5351
5352   gst_pad_start_task (demux->sinkpad,
5353       (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5354
5355   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5356
5357   return ret;
5358
5359   /* ERRORS */
5360 wrong_format:
5361   {
5362     GST_WARNING_OBJECT (demux, "seeking only supported in TIME format");
5363     return FALSE;
5364   }
5365 wrong_rate:
5366   {
5367     GST_WARNING_OBJECT (demux, "only rates > 0.0 are allowed");
5368     return FALSE;
5369   }
5370 unresolved_metadata:
5371   {
5372     gst_pad_start_task (demux->sinkpad,
5373         (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5374     GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5375     GST_WARNING_OBJECT (demux, "metadata can't be resolved");
5376     return FALSE;
5377   }
5378
5379 invalid_position:
5380   {
5381     if (flush) {
5382       GstEvent *e;
5383
5384       /* Stop flushing, the sinks are at time 0 now */
5385       e = gst_event_new_flush_stop (TRUE);
5386       gst_event_set_seqnum (e, seqnum);
5387       gst_mxf_demux_push_src_event (demux, e);
5388     }
5389     gst_pad_start_task (demux->sinkpad,
5390         (GstTaskFunction) gst_mxf_demux_loop, demux->sinkpad, NULL);
5391     GST_PAD_STREAM_UNLOCK (demux->sinkpad);
5392     GST_WARNING_OBJECT (demux, "Requested seek position is not valid");
5393     return FALSE;
5394   }
5395 }
5396
5397 static gboolean
5398 gst_mxf_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
5399 {
5400   GstMXFDemux *demux = GST_MXF_DEMUX (parent);
5401   gboolean ret;
5402
5403   GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
5404
5405   switch (GST_EVENT_TYPE (event)) {
5406     case GST_EVENT_SEEK:
5407       if (demux->random_access)
5408         ret = gst_mxf_demux_seek_pull (demux, event);
5409       else
5410         ret = gst_mxf_demux_seek_push (demux, event);
5411       gst_event_unref (event);
5412       break;
5413     default:
5414       ret = gst_pad_push_event (demux->sinkpad, event);
5415       break;
5416   }
5417
5418   return ret;
5419 }
5420
5421 static gboolean
5422 gst_mxf_demux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
5423 {
5424   GstMXFDemux *demux = GST_MXF_DEMUX (parent);
5425   gboolean ret = FALSE;
5426   GstMXFDemuxPad *mxfpad = GST_MXF_DEMUX_PAD (pad);
5427
5428   GST_DEBUG_OBJECT (pad, "handling query %s",
5429       gst_query_type_get_name (GST_QUERY_TYPE (query)));
5430
5431   switch (GST_QUERY_TYPE (query)) {
5432     case GST_QUERY_POSITION:
5433     {
5434       GstFormat format;
5435       gint64 pos;
5436
5437       gst_query_parse_position (query, &format, NULL);
5438       if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
5439         goto error;
5440
5441       pos =
5442           format ==
5443           GST_FORMAT_DEFAULT ? mxfpad->current_material_track_position :
5444           mxfpad->position;
5445
5446       GST_DEBUG_OBJECT (pad,
5447           "Returning position %" G_GINT64_FORMAT " in format %s", pos,
5448           gst_format_get_name (format));
5449
5450       gst_query_set_position (query, format, pos);
5451       ret = TRUE;
5452
5453       break;
5454     }
5455     case GST_QUERY_DURATION:{
5456       gint64 duration;
5457       GstFormat format;
5458
5459       gst_query_parse_duration (query, &format, NULL);
5460       if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
5461         goto error;
5462
5463       g_rw_lock_reader_lock (&demux->metadata_lock);
5464       if (!mxfpad->material_track || !mxfpad->material_track->parent.sequence) {
5465         g_rw_lock_reader_unlock (&demux->metadata_lock);
5466         goto error;
5467       }
5468
5469       duration = mxfpad->material_track->parent.sequence->duration;
5470       if (duration <= -1)
5471         duration = -1;
5472
5473       if (duration != -1 && format == GST_FORMAT_TIME) {
5474         if (mxfpad->material_track->edit_rate.n == 0 ||
5475             mxfpad->material_track->edit_rate.d == 0) {
5476           g_rw_lock_reader_unlock (&demux->metadata_lock);
5477           goto error;
5478         }
5479
5480         duration =
5481             gst_util_uint64_scale (duration,
5482             GST_SECOND * mxfpad->material_track->edit_rate.d,
5483             mxfpad->material_track->edit_rate.n);
5484       }
5485       g_rw_lock_reader_unlock (&demux->metadata_lock);
5486
5487       GST_DEBUG_OBJECT (pad,
5488           "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
5489           gst_format_get_name (format));
5490
5491       gst_query_set_duration (query, format, duration);
5492       ret = TRUE;
5493       break;
5494     }
5495     case GST_QUERY_SEEKING:{
5496       GstFormat fmt;
5497       gint64 duration;
5498
5499       ret = TRUE;
5500       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
5501       if (fmt != GST_FORMAT_TIME) {
5502         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5503         goto done;
5504       }
5505
5506       if (!gst_pad_query_duration (pad, GST_FORMAT_TIME, &duration)) {
5507         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5508         goto done;
5509       }
5510
5511       if (demux->random_access) {
5512         gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, duration);
5513       } else {
5514         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
5515         gboolean seekable;
5516
5517         seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
5518         if (seekable)
5519           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
5520         if (seekable)
5521           gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, duration);
5522         else
5523           gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
5524
5525         gst_query_unref (peerquery);
5526       }
5527
5528       break;
5529     }
5530     case GST_QUERY_SEGMENT:{
5531       GstFormat format;
5532       gint64 start, stop;
5533
5534       format = demux->segment.format;
5535
5536       start =
5537           gst_segment_to_stream_time (&demux->segment, format,
5538           demux->segment.start);
5539       if ((stop = demux->segment.stop) == -1)
5540         stop = demux->segment.duration;
5541       else
5542         stop = gst_segment_to_stream_time (&demux->segment, format, stop);
5543
5544       gst_query_set_segment (query, demux->segment.rate, format, start, stop);
5545       ret = TRUE;
5546       break;
5547     }
5548     default:
5549       ret = gst_pad_query_default (pad, parent, query);
5550       break;
5551   }
5552
5553 done:
5554   return ret;
5555
5556   /* ERRORS */
5557 error:
5558   {
5559     GST_DEBUG_OBJECT (pad, "query failed");
5560     goto done;
5561   }
5562 }
5563
5564 static gboolean
5565 gst_mxf_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
5566 {
5567   GstQuery *query;
5568   GstPadMode mode = GST_PAD_MODE_PUSH;
5569
5570   query = gst_query_new_scheduling ();
5571
5572   if (gst_pad_peer_query (sinkpad, query)) {
5573     if (gst_query_has_scheduling_mode_with_flags (query,
5574             GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE)) {
5575       GstSchedulingFlags flags;
5576       gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
5577       if (!(flags & GST_SCHEDULING_FLAG_SEQUENTIAL))
5578         mode = GST_PAD_MODE_PULL;
5579     }
5580   }
5581   gst_query_unref (query);
5582
5583   return gst_pad_activate_mode (sinkpad, mode, TRUE);
5584 }
5585
5586 static gboolean
5587 gst_mxf_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5588     GstPadMode mode, gboolean active)
5589 {
5590   GstMXFDemux *demux;
5591
5592   demux = GST_MXF_DEMUX (parent);
5593
5594   if (mode == GST_PAD_MODE_PUSH) {
5595     demux->random_access = FALSE;
5596   } else {
5597     if (active) {
5598       demux->random_access = TRUE;
5599       return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_mxf_demux_loop,
5600           sinkpad, NULL);
5601     } else {
5602       demux->random_access = FALSE;
5603       return gst_pad_stop_task (sinkpad);
5604     }
5605   }
5606
5607   return TRUE;
5608 }
5609
5610 static gboolean
5611 gst_mxf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
5612 {
5613   GstMXFDemux *demux;
5614   gboolean ret = FALSE;
5615
5616   demux = GST_MXF_DEMUX (parent);
5617
5618   GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
5619
5620   switch (GST_EVENT_TYPE (event)) {
5621     case GST_EVENT_FLUSH_START:
5622       demux->flushing = TRUE;
5623       ret = gst_pad_event_default (pad, parent, event);
5624       break;
5625     case GST_EVENT_FLUSH_STOP:
5626       GST_DEBUG_OBJECT (demux, "flushing queued data in the MXF demuxer");
5627
5628       gst_adapter_clear (demux->adapter);
5629       demux->flushing = FALSE;
5630       demux->offset = 0;
5631       ret = gst_pad_event_default (pad, parent, event);
5632       break;
5633     case GST_EVENT_EOS:{
5634       GstMXFDemuxPad *p = NULL;
5635       guint i;
5636
5637       if (demux->src->len == 0) {
5638         GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
5639             ("This stream contains no data."),
5640             ("got eos and didn't find any streams"));
5641       }
5642
5643       for (i = 0; i < demux->essence_tracks->len; i++) {
5644         GstMXFDemuxEssenceTrack *t =
5645             &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack, i);
5646
5647         if (t->position > 0)
5648           t->duration = t->position;
5649       }
5650
5651       for (i = 0; i < demux->src->len; i++) {
5652         GstMXFDemuxPad *p = g_ptr_array_index (demux->src, i);
5653
5654         if (!p->eos
5655             && p->current_essence_track_position >=
5656             p->current_essence_track->duration) {
5657           p->eos = TRUE;
5658           gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5659         }
5660       }
5661
5662       while ((p = gst_mxf_demux_get_earliest_pad (demux))) {
5663         guint64 offset;
5664         gint64 position;
5665
5666         position = p->current_essence_track_position;
5667
5668         offset =
5669             gst_mxf_demux_find_essence_element (demux, p->current_essence_track,
5670             &position, FALSE);
5671         if (offset == -1) {
5672           GST_ERROR_OBJECT (demux, "Failed to find offset for essence track");
5673           p->eos = TRUE;
5674           gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5675           continue;
5676         }
5677
5678         if (gst_pad_push_event (demux->sinkpad,
5679                 gst_event_new_seek (demux->segment.rate, GST_FORMAT_BYTES,
5680                     demux->segment.flags | GST_SEEK_FLAG_ACCURATE,
5681                     GST_SEEK_TYPE_SET, offset + demux->run_in,
5682                     GST_SEEK_TYPE_NONE, 0))) {
5683
5684           for (i = 0; i < demux->essence_tracks->len; i++) {
5685             GstMXFDemuxEssenceTrack *etrack =
5686                 &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
5687                 i);
5688             etrack->position = -1;
5689           }
5690           ret = TRUE;
5691           goto out;
5692         } else {
5693           GST_WARNING_OBJECT (demux,
5694               "Seek to remaining part of the file failed");
5695           p->eos = TRUE;
5696           gst_pad_push_event (GST_PAD_CAST (p), gst_event_new_eos ());
5697           continue;
5698         }
5699       }
5700
5701       /* and one more time for good measure apparently? */
5702       gst_pad_event_default (pad, parent, event);
5703       ret = (demux->src->len > 0);
5704       break;
5705     }
5706     case GST_EVENT_SEGMENT:{
5707       guint i;
5708
5709       for (i = 0; i < demux->essence_tracks->len; i++) {
5710         GstMXFDemuxEssenceTrack *t =
5711             &g_array_index (demux->essence_tracks, GstMXFDemuxEssenceTrack,
5712             i);
5713         t->position = -1;
5714       }
5715       demux->current_partition = NULL;
5716       demux->seqnum = gst_event_get_seqnum (event);
5717       gst_event_unref (event);
5718       ret = TRUE;
5719       break;
5720     }
5721     default:
5722       ret = gst_pad_event_default (pad, parent, event);
5723       break;
5724   }
5725
5726 out:
5727
5728   return ret;
5729 }
5730
5731 static gboolean
5732 gst_mxf_demux_query (GstElement * element, GstQuery * query)
5733 {
5734   GstMXFDemux *demux = GST_MXF_DEMUX (element);
5735   gboolean ret = FALSE;
5736
5737   GST_DEBUG_OBJECT (demux, "handling query %s",
5738       gst_query_type_get_name (GST_QUERY_TYPE (query)));
5739
5740   switch (GST_QUERY_TYPE (query)) {
5741     case GST_QUERY_POSITION:
5742     {
5743       GstFormat format;
5744       gint64 pos;
5745
5746       gst_query_parse_position (query, &format, NULL);
5747       if (format != GST_FORMAT_TIME)
5748         goto error;
5749
5750       pos = demux->segment.position;
5751
5752       GST_DEBUG_OBJECT (demux,
5753           "Returning position %" G_GINT64_FORMAT " in format %s", pos,
5754           gst_format_get_name (format));
5755
5756       gst_query_set_position (query, format, pos);
5757       ret = TRUE;
5758
5759       break;
5760     }
5761     case GST_QUERY_DURATION:{
5762       gint64 duration = -1;
5763       GstFormat format;
5764       guint i;
5765
5766       gst_query_parse_duration (query, &format, NULL);
5767       if (format != GST_FORMAT_TIME)
5768         goto error;
5769
5770       if (demux->src->len == 0)
5771         goto done;
5772
5773       g_rw_lock_reader_lock (&demux->metadata_lock);
5774       for (i = 0; i < demux->src->len; i++) {
5775         GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
5776         gint64 pdur = -1;
5777
5778         if (!pad->material_track || !pad->material_track->parent.sequence)
5779           continue;
5780
5781         pdur = pad->material_track->parent.sequence->duration;
5782         if (pad->material_track->edit_rate.n == 0 ||
5783             pad->material_track->edit_rate.d == 0 || pdur <= -1)
5784           continue;
5785
5786         pdur =
5787             gst_util_uint64_scale (pdur,
5788             GST_SECOND * pad->material_track->edit_rate.d,
5789             pad->material_track->edit_rate.n);
5790         duration = MAX (duration, pdur);
5791       }
5792       g_rw_lock_reader_unlock (&demux->metadata_lock);
5793
5794       if (duration == -1) {
5795         GST_DEBUG_OBJECT (demux, "No duration known (yet)");
5796         goto done;
5797       }
5798
5799       GST_DEBUG_OBJECT (demux,
5800           "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
5801           gst_format_get_name (format));
5802
5803       gst_query_set_duration (query, format, duration);
5804       ret = TRUE;
5805       break;
5806     }
5807     case GST_QUERY_SEEKING:{
5808       GstFormat fmt;
5809
5810       ret = TRUE;
5811       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
5812       if (fmt != GST_FORMAT_TIME) {
5813         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
5814         goto done;
5815       }
5816
5817       if (demux->random_access) {
5818         gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
5819       } else {
5820         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
5821         gboolean seekable;
5822
5823         seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
5824         if (seekable)
5825           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
5826         if (seekable)
5827           gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
5828         else
5829           gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
5830
5831         gst_query_unref (peerquery);
5832       }
5833
5834       break;
5835     }
5836     case GST_QUERY_SEGMENT:{
5837       GstFormat format;
5838       gint64 start, stop;
5839
5840       format = demux->segment.format;
5841
5842       start =
5843           gst_segment_to_stream_time (&demux->segment, format,
5844           demux->segment.start);
5845       if ((stop = demux->segment.stop) == -1)
5846         stop = demux->segment.duration;
5847       else
5848         stop = gst_segment_to_stream_time (&demux->segment, format, stop);
5849
5850       gst_query_set_segment (query, demux->segment.rate, format, start, stop);
5851       ret = TRUE;
5852       break;
5853     }
5854     default:
5855       /* else forward upstream */
5856       ret = gst_pad_peer_query (demux->sinkpad, query);
5857       break;
5858   }
5859
5860 done:
5861   return ret;
5862
5863   /* ERRORS */
5864 error:
5865   {
5866     GST_DEBUG_OBJECT (demux, "query failed");
5867     goto done;
5868   }
5869 }
5870
5871 static GstStateChangeReturn
5872 gst_mxf_demux_change_state (GstElement * element, GstStateChange transition)
5873 {
5874   GstMXFDemux *demux = GST_MXF_DEMUX (element);
5875   GstStateChangeReturn ret;
5876
5877   switch (transition) {
5878     case GST_STATE_CHANGE_READY_TO_PAUSED:
5879       demux->seqnum = gst_util_seqnum_next ();
5880       break;
5881     default:
5882       break;
5883   }
5884
5885   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
5886   if (ret == GST_STATE_CHANGE_FAILURE)
5887     return ret;
5888
5889   switch (transition) {
5890     case GST_STATE_CHANGE_PAUSED_TO_READY:
5891       gst_mxf_demux_reset (demux);
5892       break;
5893     default:
5894       break;
5895   }
5896
5897   return ret;
5898 }
5899
5900 static void
5901 gst_mxf_demux_set_property (GObject * object, guint prop_id,
5902     const GValue * value, GParamSpec * pspec)
5903 {
5904   GstMXFDemux *demux = GST_MXF_DEMUX (object);
5905
5906   switch (prop_id) {
5907     case PROP_PACKAGE:
5908       g_free (demux->requested_package_string);
5909       demux->requested_package_string = g_value_dup_string (value);
5910       break;
5911     case PROP_MAX_DRIFT:
5912       demux->max_drift = g_value_get_uint64 (value);
5913       break;
5914     default:
5915       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5916       break;
5917   }
5918 }
5919
5920 static void
5921 gst_mxf_demux_get_property (GObject * object, guint prop_id,
5922     GValue * value, GParamSpec * pspec)
5923 {
5924   GstMXFDemux *demux = GST_MXF_DEMUX (object);
5925
5926   switch (prop_id) {
5927     case PROP_PACKAGE:
5928       g_value_set_string (value, demux->current_package_string);
5929       break;
5930     case PROP_MAX_DRIFT:
5931       g_value_set_uint64 (value, demux->max_drift);
5932       break;
5933     case PROP_STRUCTURE:{
5934       GstStructure *s;
5935
5936       g_rw_lock_reader_lock (&demux->metadata_lock);
5937       if (demux->preface &&
5938           MXF_METADATA_BASE (demux->preface)->resolved ==
5939           MXF_METADATA_BASE_RESOLVE_STATE_SUCCESS)
5940         s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
5941       else
5942         s = NULL;
5943
5944       gst_value_set_structure (value, s);
5945
5946       if (s)
5947         gst_structure_free (s);
5948
5949       g_rw_lock_reader_unlock (&demux->metadata_lock);
5950       break;
5951     }
5952     default:
5953       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5954       break;
5955   }
5956 }
5957
5958 static void
5959 gst_mxf_demux_finalize (GObject * object)
5960 {
5961   GstMXFDemux *demux = GST_MXF_DEMUX (object);
5962
5963   gst_mxf_demux_reset (demux);
5964
5965   if (demux->adapter) {
5966     g_object_unref (demux->adapter);
5967     demux->adapter = NULL;
5968   }
5969
5970   if (demux->flowcombiner) {
5971     gst_flow_combiner_free (demux->flowcombiner);
5972     demux->flowcombiner = NULL;
5973   }
5974
5975   if (demux->close_seg_event) {
5976     gst_event_unref (demux->close_seg_event);
5977     demux->close_seg_event = NULL;
5978   }
5979
5980   g_free (demux->current_package_string);
5981   demux->current_package_string = NULL;
5982   g_free (demux->requested_package_string);
5983   demux->requested_package_string = NULL;
5984
5985   g_ptr_array_free (demux->src, TRUE);
5986   demux->src = NULL;
5987   g_array_free (demux->essence_tracks, TRUE);
5988   demux->essence_tracks = NULL;
5989
5990   g_hash_table_destroy (demux->metadata);
5991
5992   g_rw_lock_clear (&demux->metadata_lock);
5993
5994   G_OBJECT_CLASS (parent_class)->finalize (object);
5995 }
5996
5997 static void
5998 gst_mxf_demux_class_init (GstMXFDemuxClass * klass)
5999 {
6000   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
6001   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
6002
6003   GST_DEBUG_CATEGORY_INIT (mxfdemux_debug, "mxfdemux", 0, "MXF demuxer");
6004
6005   parent_class = g_type_class_peek_parent (klass);
6006
6007   gobject_class->finalize = gst_mxf_demux_finalize;
6008   gobject_class->set_property = gst_mxf_demux_set_property;
6009   gobject_class->get_property = gst_mxf_demux_get_property;
6010
6011   g_object_class_install_property (gobject_class, PROP_PACKAGE,
6012       g_param_spec_string ("package", "Package",
6013           "Material or Source package to use for playback", NULL,
6014           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6015
6016   g_object_class_install_property (gobject_class, PROP_MAX_DRIFT,
6017       g_param_spec_uint64 ("max-drift", "Maximum drift",
6018           "Maximum number of nanoseconds by which tracks can differ",
6019           100 * GST_MSECOND, G_MAXUINT64, DEFAULT_MAX_DRIFT,
6020           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6021
6022   g_object_class_install_property (gobject_class, PROP_STRUCTURE,
6023       g_param_spec_boxed ("structure", "Structure",
6024           "Structural metadata of the MXF file",
6025           GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6026
6027   gstelement_class->change_state =
6028       GST_DEBUG_FUNCPTR (gst_mxf_demux_change_state);
6029   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_mxf_demux_query);
6030
6031   gst_element_class_add_static_pad_template (gstelement_class,
6032       &mxf_sink_template);
6033   gst_element_class_add_static_pad_template (gstelement_class,
6034       &mxf_src_template);
6035   gst_element_class_set_static_metadata (gstelement_class, "MXF Demuxer",
6036       "Codec/Demuxer", "Demux MXF files",
6037       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
6038 }
6039
6040 static void
6041 gst_mxf_demux_init (GstMXFDemux * demux)
6042 {
6043   demux->sinkpad =
6044       gst_pad_new_from_static_template (&mxf_sink_template, "sink");
6045
6046   gst_pad_set_event_function (demux->sinkpad,
6047       GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_event));
6048   gst_pad_set_chain_function (demux->sinkpad,
6049       GST_DEBUG_FUNCPTR (gst_mxf_demux_chain));
6050   gst_pad_set_activate_function (demux->sinkpad,
6051       GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate));
6052   gst_pad_set_activatemode_function (demux->sinkpad,
6053       GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_mode));
6054
6055   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
6056
6057   demux->max_drift = DEFAULT_MAX_DRIFT;
6058
6059   demux->adapter = gst_adapter_new ();
6060   demux->flowcombiner = gst_flow_combiner_new ();
6061   g_rw_lock_init (&demux->metadata_lock);
6062
6063   demux->src = g_ptr_array_new ();
6064   demux->essence_tracks =
6065       g_array_new (FALSE, FALSE, sizeof (GstMXFDemuxEssenceTrack));
6066
6067   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
6068
6069   gst_mxf_demux_reset (demux);
6070 }