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