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