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