summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorSebastian Dröge <slomo@circular-chaos.org>2008-11-21 10:27:15 +0000
committerSebastian Dröge <slomo@circular-chaos.org>2008-11-21 10:27:15 +0000
commite76ea1ca88b2b9fb92484a95c216ab4db714f792 (patch)
tree4a4f74b83fa3087df320727de3d058484a37428d /gst
parentbba82abbf7edd7b7751af53a817622d13b5ab577 (diff)
downloadgst-plugins-bad-e76ea1ca88b2b9fb92484a95c216ab4db714f792.tar.gz
gst-plugins-bad-e76ea1ca88b2b9fb92484a95c216ab4db714f792.tar.bz2
gst-plugins-bad-e76ea1ca88b2b9fb92484a95c216ab4db714f792.zip
Add first version of an MXF demuxer. Currently it supports
Original commit message from CVS: * configure.ac: * gst/mxf/Makefile.am: * gst/mxf/mxf.c: (plugin_init): * gst/mxf/mxfaes-bwf.c: (mxf_metadata_wave_audio_essence_descriptor_parse), (mxf_metadata_wave_audio_essence_descriptor_reset), (mxf_is_aes_bwf_essence_track), (mxf_bwf_handle_essence_element), (mxf_bwf_create_caps), (mxf_aes_bwf_create_caps): * gst/mxf/mxfaes-bwf.h: * gst/mxf/mxfdemux.c: (gst_mxf_pad_finalize), (gst_mxf_pad_class_init), (gst_mxf_pad_init), (gst_mxf_demux_flush), (gst_mxf_demux_remove_pad), (gst_mxf_demux_reset_mxf_state), (gst_mxf_demux_reset_metadata), (gst_mxf_demux_reset), (gst_mxf_demux_pull_range), (gst_mxf_demux_push_src_event), (gst_mxf_demux_handle_partition_pack), (gst_mxf_demux_handle_primer_pack), (gst_mxf_demux_handle_metadata_preface), (gst_mxf_demux_handle_metadata_identification), (gst_mxf_demux_handle_metadata_content_storage), (gst_mxf_demux_handle_metadata_essence_container_data), (gst_mxf_demux_handle_metadata_material_package), (gst_mxf_demux_handle_metadata_source_package), (gst_mxf_demux_handle_metadata_track), (gst_mxf_demux_handle_metadata_sequence), (gst_mxf_demux_handle_metadata_structural_component), (gst_mxf_demux_handle_metadata_generic_descriptor), (gst_mxf_demux_handle_metadata_file_descriptor), (gst_mxf_demux_handle_metadata_multiple_descriptor), (gst_mxf_demux_handle_metadata_generic_picture_essence_descriptor), (gst_mxf_demux_handle_metadata_cdci_picture_essence_descriptor), (gst_mxf_demux_handle_metadata_mpeg_video_descriptor), (gst_mxf_demux_handle_metadata_generic_sound_essence_descriptor), (gst_mxf_demux_handle_metadata_wave_audio_essence_descriptor), (gst_mxf_demux_handle_metadata_locator), (gst_mxf_demux_handle_header_metadata_resolve_references), (gst_mxf_demux_handle_header_metadata_update_streams), (gst_mxf_demux_handle_metadata), (gst_mxf_demux_handle_generic_container_system_item), (gst_mxf_demux_handle_generic_container_essence_element), (gst_mxf_demux_handle_random_index_pack), (gst_mxf_demux_handle_index_table_segment), (gst_mxf_demux_pull_klv_packet), (gst_mxf_demux_parse_footer_metadata), (gst_mxf_demux_handle_klv_packet), (gst_mxf_demux_pull_and_handle_klv_packet), (gst_mxf_demux_loop), (gst_mxf_demux_chain), (gst_mxf_demux_src_event), (gst_mxf_demux_src_query_type), (gst_mxf_demux_src_query), (gst_mxf_demux_sink_activate), (gst_mxf_demux_sink_activate_push), (gst_mxf_demux_sink_activate_pull), (gst_mxf_demux_sink_event), (gst_mxf_demux_change_state), (gst_mxf_demux_finalize), (gst_mxf_demux_base_init), (gst_mxf_demux_class_init), (gst_mxf_demux_init): * gst/mxf/mxfdemux.h: * gst/mxf/mxfmpeg.c: (mxf_metadata_mpeg_video_descriptor_parse), (mxf_metadata_mpeg_video_descriptor_reset), (mxf_is_mpeg_video_essence_track), (mxf_mpeg_video_handle_essence_element), (mxf_mpeg_video_create_caps): * gst/mxf/mxfmpeg.h: * gst/mxf/mxfparse.c: (mxf_is_mxf_packet), (mxf_is_partition_pack), (mxf_is_header_partition_pack), (mxf_is_body_partition_pack), (mxf_is_footer_partition_pack), (mxf_is_fill), (mxf_is_primer_pack), (mxf_is_metadata), (mxf_is_random_index_pack), (mxf_is_index_table_segment), (mxf_is_generic_container_system_item), (mxf_is_generic_container_essence_element), (mxf_is_generic_container_essence_container_label), (mxf_ul_is_equal), (mxf_ul_is_zero), (mxf_ul_to_string), (mxf_umid_is_equal), (mxf_umid_is_zero), (mxf_umid_to_string), (gst_mxf_ul_hash), (gst_mxf_ul_equal), (mxf_timestamp_parse), (mxf_timestamp_is_unknown), (mxf_timestamp_compare), (mxf_fraction_parse), (mxf_utf16_to_utf8), (mxf_product_version_parse), (mxf_partition_pack_parse), (mxf_partition_pack_reset), (_mxf_mapping_ul_free), (mxf_primer_pack_parse), (mxf_primer_pack_reset), (mxf_local_tag_parse), (gst_mxf_local_tag_free), (gst_metadata_add_custom_tag), (mxf_metadata_preface_parse), (mxf_metadata_preface_reset), (mxf_metadata_identification_parse), (mxf_metadata_identification_reset), (mxf_metadata_content_storage_parse), (mxf_metadata_content_storage_reset), (mxf_metadata_essence_container_data_parse), (mxf_metadata_essence_container_data_reset), (mxf_metadata_generic_package_parse), (mxf_metadata_generic_package_reset), (mxf_metadata_track_parse), (mxf_metadata_track_reset), (mxf_metadata_track_identifier_parse), (mxf_metadata_sequence_parse), (mxf_metadata_sequence_reset), (mxf_metadata_structural_component_parse), (mxf_metadata_structural_component_reset), (mxf_metadata_generic_descriptor_parse), (mxf_metadata_generic_descriptor_reset), (mxf_metadata_file_descriptor_parse), (mxf_metadata_file_descriptor_reset), (mxf_metadata_generic_sound_essence_descriptor_parse), (mxf_metadata_generic_sound_essence_descriptor_reset), (mxf_metadata_generic_picture_essence_descriptor_parse), (mxf_metadata_generic_picture_essence_descriptor_reset), (mxf_metadata_cdci_picture_essence_descriptor_parse), (mxf_metadata_cdci_picture_essence_descriptor_reset), (mxf_metadata_multiple_descriptor_parse), (mxf_metadata_multiple_descriptor_reset), (mxf_metadata_locator_parse), (mxf_metadata_locator_reset): * gst/mxf/mxfparse.h: * gst/mxf/mxftypes.h: Add first version of an MXF demuxer. Currently it supports MPEG video and raw audio and OP 1a/b/c.
Diffstat (limited to 'gst')
-rw-r--r--gst/mxf/Makefile.am20
-rw-r--r--gst/mxf/mxf.c46
-rw-r--r--gst/mxf/mxfaes-bwf.c382
-rw-r--r--gst/mxf/mxfaes-bwf.h66
-rw-r--r--gst/mxf/mxfdemux.c2859
-rw-r--r--gst/mxf/mxfdemux.h108
-rw-r--r--gst/mxf/mxfmpeg.c318
-rw-r--r--gst/mxf/mxfmpeg.h60
-rw-r--r--gst/mxf/mxfparse.c2692
-rw-r--r--gst/mxf/mxfparse.h129
-rw-r--r--gst/mxf/mxftypes.h463
11 files changed, 7143 insertions, 0 deletions
diff --git a/gst/mxf/Makefile.am b/gst/mxf/Makefile.am
new file mode 100644
index 00000000..0113d9d1
--- /dev/null
+++ b/gst/mxf/Makefile.am
@@ -0,0 +1,20 @@
+plugin_LTLIBRARIES = libgstmxf.la
+
+libgstmxf_la_SOURCES = \
+ mxf.c \
+ mxfdemux.c \
+ mxfparse.c \
+ mxfaes-bwf.c \
+ mxfmpeg.c
+
+libgstmxf_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgstmxf_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
+libgstmxf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+ mxfdemux.h \
+ mxfparse.h \
+ mxfaes-bwf.h \
+ mxfmpeg.h \
+ mxftypes.h
+
diff --git a/gst/mxf/mxf.c b/gst/mxf/mxf.c
new file mode 100644
index 00000000..655ac311
--- /dev/null
+++ b/gst/mxf/mxf.c
@@ -0,0 +1,46 @@
+/* GStreamer
+ * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/gst.h>
+
+#include "mxfdemux.h"
+
+GST_DEBUG_CATEGORY (mxf_debug);
+#define GST_CAT_DEFAULT mxf_debug
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "mxfdemux", GST_RANK_PRIMARY,
+ GST_TYPE_MXF_DEMUX))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (mxf_debug, "mxf", 0, "MXF");
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "mxf",
+ "MXF plugin library",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/mxf/mxfaes-bwf.c b/gst/mxf/mxfaes-bwf.c
new file mode 100644
index 00000000..ef97fafc
--- /dev/null
+++ b/gst/mxf/mxfaes-bwf.c
@@ -0,0 +1,382 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Implementation of SMPTE 382M - Mapping AES3 and Broadcast Wave
+ * Audio into the MXF Generic Container
+ */
+
+/* TODO:
+ * - Handle the case were a track only references specific channels
+ * of the essence (ChannelID property)
+ * - Add support for more codecs
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+
+#include "mxfaes-bwf.h"
+
+GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
+#define GST_CAT_DEFAULT mxf_debug
+
+/* SMPTE 382M Annex 1 */
+gboolean
+mxf_metadata_wave_audio_essence_descriptor_parse (const MXFUL * key,
+ MXFMetadataWaveAudioEssenceDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataWaveAudioEssenceDescriptor));
+
+ if (!mxf_metadata_generic_sound_essence_descriptor_parse (key,
+ (MXFMetadataGenericSoundEssenceDescriptor *) descriptor, primer, type,
+ data, size))
+ goto error;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3d0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 2)
+ goto error;
+ descriptor->block_align = GST_READ_UINT16_BE (tag_data);
+ break;
+ case 0x3d0b:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->sequence_offset = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3d09:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->avg_bps = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d32:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->channel_assignment, tag_data, 16);
+ break;
+ case 0x3d29:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->peak_envelope_version = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d2a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->peak_envelope_format = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d2b:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->points_per_peak_value = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d2c:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->peak_envelope_block_size = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d2d:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->peak_channels = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d2e:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->peak_frames = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d2f:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ descriptor->peak_of_peaks_position = GST_READ_UINT64_BE (tag_data);
+ break;
+ case 0x3d30:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!mxf_timestamp_parse (&descriptor->peak_envelope_timestamp,
+ tag_data, tag_size))
+ goto error;
+ break;
+ case 0x3d31:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ descriptor->peak_envelope_data = g_memdup (tag_data, tag_size);
+ descriptor->peak_envelope_data_length = tag_size;
+ break;
+ default:
+ if (type != MXF_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR)
+ goto next;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed wave audio essence descriptor:");
+ GST_DEBUG (" block align = %u", descriptor->block_align);
+ GST_DEBUG (" sequence offset = %u", descriptor->sequence_offset);
+ GST_DEBUG (" average bps = %u", descriptor->avg_bps);
+ GST_DEBUG (" channel assignment = %s",
+ mxf_ul_to_string (&descriptor->channel_assignment, str));
+ GST_DEBUG (" peak envelope version = %u", descriptor->peak_envelope_version);
+ GST_DEBUG (" peak envelope format = %u", descriptor->peak_envelope_format);
+ GST_DEBUG (" points per peak value = %u", descriptor->points_per_peak_value);
+ GST_DEBUG (" peak envelope block size = %u",
+ descriptor->peak_envelope_block_size);
+ GST_DEBUG (" peak channels = %u", descriptor->peak_channels);
+ GST_DEBUG (" peak frames = %u", descriptor->peak_frames);
+ GST_DEBUG (" peak of peaks position = %" G_GINT64_FORMAT,
+ descriptor->peak_of_peaks_position);
+ GST_DEBUG (" peak envelope timestamp = %d/%u/%u %u:%u:%u.%u",
+ descriptor->peak_envelope_timestamp.year,
+ descriptor->peak_envelope_timestamp.month,
+ descriptor->peak_envelope_timestamp.day,
+ descriptor->peak_envelope_timestamp.hour,
+ descriptor->peak_envelope_timestamp.minute,
+ descriptor->peak_envelope_timestamp.second,
+ (descriptor->peak_envelope_timestamp.quarter_msecond * 1000) / 256);
+
+ GST_DEBUG (" peak evelope data size = %u",
+ descriptor->peak_envelope_data_length);
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid wave audio essence descriptor");
+ mxf_metadata_wave_audio_essence_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void mxf_metadata_wave_audio_essence_descriptor_reset
+ (MXFMetadataWaveAudioEssenceDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ mxf_metadata_generic_sound_essence_descriptor_reset (
+ (MXFMetadataGenericSoundEssenceDescriptor *) descriptor);
+
+ memset (descriptor, 0, sizeof (MXFMetadataWaveAudioEssenceDescriptor));
+}
+
+gboolean
+mxf_is_aes_bwf_essence_track (const MXFMetadataTrack * track)
+{
+ guint i;
+
+ g_return_val_if_fail (track != NULL, FALSE);
+
+ if (track->descriptor == NULL) {
+ GST_ERROR ("No descriptor for this track");
+ return FALSE;
+ }
+
+ for (i = 0; i < track->n_descriptor; i++) {
+ MXFMetadataFileDescriptor *d = track->descriptor[i];
+ MXFUL *key = &d->essence_container;
+ /* SMPTE 382M 9 */
+ if (mxf_is_generic_container_essence_container_label (key) &&
+ key->u[12] == 0x02 &&
+ key->u[13] == 0x06 &&
+ (key->u[14] == 0x01 ||
+ key->u[14] == 0x02 ||
+ key->u[14] == 0x03 ||
+ key->u[14] == 0x04 || key->u[14] == 0x08 || key->u[14] == 0x09))
+ return TRUE;
+ }
+
+
+ return FALSE;
+}
+
+static GstFlowReturn
+mxf_bwf_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
+ GstCaps * caps, MXFMetadataGenericPackage * package,
+ MXFMetadataTrack * track, MXFMetadataStructuralComponent * component,
+ gpointer mapping_data, GstBuffer ** outbuf)
+{
+ *outbuf = buffer;
+
+ /* SMPTE 382M Table 1: Check if this is some kind of Wave element */
+ if (key->u[12] != 0x16 || (key->u[14] != 0x01 && key->u[14] != 0x02
+ && key->u[14] != 0x0b)) {
+ GST_ERROR ("Invalid BWF essence element");
+ return GST_FLOW_ERROR;
+ }
+
+ /* FIXME: check if the size is a multiply of the unit size, ... */
+ return GST_FLOW_OK;
+}
+
+/* SMPTE RP224 */
+static const MXFUL mxf_sound_essence_compression_uncompressed =
+ { {0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x01, 0x04, 0x02, 0x02, 0x01,
+ 0x7F, 0x00, 0x00, 0x00}
+};
+static const MXFUL mxf_sound_essence_compression_aiff =
+ { {0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x07, 0x04, 0x02, 0x02, 0x01,
+ 0x7E, 0x00, 0x00, 0x00}
+};
+
+static GstCaps *
+mxf_bwf_create_caps (MXFMetadataGenericPackage * package,
+ MXFMetadataTrack * track,
+ MXFMetadataGenericSoundEssenceDescriptor * descriptor, GstTagList ** tags,
+ MXFEssenceElementHandler * handler, gpointer * mapping_data)
+{
+ GstCaps *ret = NULL;
+ MXFMetadataWaveAudioEssenceDescriptor *wa_descriptor = NULL;
+ gchar str[48];
+
+ if (((MXFMetadataGenericDescriptor *) descriptor)->type ==
+ MXF_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR)
+ wa_descriptor = (MXFMetadataWaveAudioEssenceDescriptor *) descriptor;
+
+ /* TODO: set caps for avg bitrate, audio codec, ...... */
+ /* TODO: Handle width=!depth, needs shifting of samples */
+
+ /* FIXME: set a channel layout */
+
+ if (mxf_ul_is_zero (&descriptor->sound_essence_compression) ||
+ mxf_ul_is_equal (&descriptor->sound_essence_compression,
+ &mxf_sound_essence_compression_uncompressed)) {
+ guint block_align;
+
+ if (descriptor->channel_count == 0 ||
+ descriptor->quantization_bits == 0 ||
+ descriptor->audio_sampling_rate.n == 0 ||
+ descriptor->audio_sampling_rate.d == 0) {
+ GST_ERROR ("Invalid descriptor");
+ return NULL;
+ }
+ if (wa_descriptor)
+ block_align = wa_descriptor->block_align;
+ else
+ block_align = GST_ROUND_UP_8 (descriptor->quantization_bits) / 8;
+
+ ret = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT,
+ (gint) (((gdouble) descriptor->audio_sampling_rate.n) /
+ ((gdouble) descriptor->audio_sampling_rate.d) + 0.5), "channels",
+ G_TYPE_INT, descriptor->channel_count, "signed", G_TYPE_BOOLEAN,
+ (block_align != 1), "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, "depth",
+ G_TYPE_INT, (block_align / descriptor->channel_count) * 8, "width",
+ G_TYPE_INT, (block_align / descriptor->channel_count) * 8, NULL);
+ } else if (mxf_ul_is_equal (&descriptor->sound_essence_compression,
+ &mxf_sound_essence_compression_aiff)) {
+ guint block_align;
+
+ if (descriptor->channel_count == 0 ||
+ descriptor->quantization_bits == 0 ||
+ descriptor->audio_sampling_rate.n == 0 ||
+ descriptor->audio_sampling_rate.d == 0) {
+ GST_ERROR ("Invalid descriptor");
+ return NULL;
+ }
+
+ if (wa_descriptor)
+ block_align = wa_descriptor->block_align;
+ else
+ block_align = GST_ROUND_UP_8 (descriptor->quantization_bits) / 8;
+
+ ret = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT,
+ (gint) (((gdouble) descriptor->audio_sampling_rate.n) /
+ ((gdouble) descriptor->audio_sampling_rate.d) + 0.5), "channels",
+ G_TYPE_INT, descriptor->channel_count, "signed", G_TYPE_BOOLEAN,
+ (block_align != 1), "endianness", G_TYPE_INT, G_BIG_ENDIAN, "depth",
+ G_TYPE_INT, (block_align / descriptor->channel_count) * 8, "width",
+ G_TYPE_INT, (block_align / descriptor->channel_count) * 8, NULL);
+ } else {
+ GST_ERROR ("Unsupported sound essence compression: %s",
+ mxf_ul_to_string (&descriptor->sound_essence_compression, str));
+ }
+
+ *handler = mxf_bwf_handle_essence_element;
+
+ return ret;
+}
+
+GstCaps *
+mxf_aes_bwf_create_caps (MXFMetadataGenericPackage * package,
+ MXFMetadataTrack * track, GstTagList ** tags,
+ MXFEssenceElementHandler * handler, gpointer * mapping_data)
+{
+ MXFMetadataGenericSoundEssenceDescriptor *s = NULL;
+ guint i;
+
+ g_return_val_if_fail (package != NULL, NULL);
+ g_return_val_if_fail (track != NULL, NULL);
+
+ if (track->descriptor == NULL) {
+ GST_ERROR ("No descriptor found for this track");
+ return NULL;
+ }
+
+ /* TODO: handle AES3 audio */
+
+ for (i = 0; i < track->n_descriptor; i++) {
+ if ((track->descriptor[i]->parent.type ==
+ MXF_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR
+ || track->descriptor[i]->parent.type ==
+ MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR)
+ && (track->descriptor[i]->essence_container.u[14] == 0x01
+ || track->descriptor[i]->essence_container.u[14] == 0x02
+ || track->descriptor[i]->essence_container.u[14] == 0x08)) {
+ s = (MXFMetadataGenericSoundEssenceDescriptor *) track->descriptor[i];
+ break;
+ }
+ }
+
+ if (!s) {
+ GST_ERROR ("No descriptor found for this track");
+ return NULL;
+ } else if (s) {
+ return mxf_bwf_create_caps (package, track, s, tags, handler, mapping_data);
+ }
+
+ return NULL;
+}
diff --git a/gst/mxf/mxfaes-bwf.h b/gst/mxf/mxfaes-bwf.h
new file mode 100644
index 00000000..6f3a5cd4
--- /dev/null
+++ b/gst/mxf/mxfaes-bwf.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Implementation of SMPTE 382M - Mapping AES3 and Broadcast Wave
+ * Audio into the MXF Generic Container
+ */
+
+#ifndef __MXF_AES_BWF_H__
+#define __MXF_AES_BWF_H__
+
+#include <gst/gst.h>
+
+#include "mxfparse.h"
+
+/* SMPTE 382M Annex 1 */
+#define MXF_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR 0x0148
+
+/* SMPTE 382M Annex 1 */
+typedef struct {
+ MXFMetadataGenericSoundEssenceDescriptor parent;
+
+ guint16 block_align;
+ guint8 sequence_offset;
+
+ guint32 avg_bps;
+
+ MXFUL channel_assignment;
+
+ guint32 peak_envelope_version;
+ guint32 peak_envelope_format;
+ guint32 points_per_peak_value;
+ guint32 peak_envelope_block_size;
+ guint32 peak_channels;
+ guint32 peak_frames;
+ gint64 peak_of_peaks_position;
+ MXFTimestamp peak_envelope_timestamp;
+
+ guint8 *peak_envelope_data;
+ guint16 peak_envelope_data_length;
+} MXFMetadataWaveAudioEssenceDescriptor;
+
+gboolean mxf_metadata_wave_audio_essence_descriptor_parse (const MXFUL *key, MXFMetadataWaveAudioEssenceDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_wave_audio_essence_descriptor_reset (MXFMetadataWaveAudioEssenceDescriptor *descriptor);
+
+gboolean mxf_is_aes_bwf_essence_track (const MXFMetadataTrack *track);
+
+GstCaps *
+mxf_aes_bwf_create_caps (MXFMetadataGenericPackage *package, MXFMetadataTrack *track, GstTagList **tags, MXFEssenceElementHandler *handler, gpointer *mapping_data);
+
+#endif /* __MXF_AES_BWF_H__ */
diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c
new file mode 100644
index 00000000..ce3c5abe
--- /dev/null
+++ b/gst/mxf/mxfdemux.c
@@ -0,0 +1,2859 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* TODO:
+ * - start at correct position of the component, switch components
+ * - RandomIndex / IndexSegment support
+ * - timecode tracks
+ * - descriptive metadata
+ * - generic container system items
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mxfdemux.h"
+#include "mxfparse.h"
+#include "mxfaes-bwf.h"
+#include "mxfmpeg.h"
+
+#include <string.h>
+
+static GstStaticPadTemplate mxf_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/mxf")
+ );
+
+static GstStaticPadTemplate audio_src_template =
+GST_STATIC_PAD_TEMPLATE ("audio_%d",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate video_src_template =
+GST_STATIC_PAD_TEMPLATE ("video_%d",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate data_src_template =
+GST_STATIC_PAD_TEMPLATE ("data_%d",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (mxfdemux_debug);
+#define GST_CAT_DEFAULT mxfdemux_debug
+
+#define GST_TYPE_MXF_PAD (gst_mxf_pad_get_type())
+#define GST_MXF_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_MXF_PAD,GstMXFPad))
+#define GST_MXF_PAD_CAST(pad) ((GstMXFPad *) pad)
+#define GST_IS_MXF_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_MXF_PAD))
+
+typedef struct
+{
+ GstPad parent;
+
+ guint32 track_id;
+ MXFMetadataTrackType track_type;
+ gboolean need_segment;
+
+ guint64 essence_element_count;
+ MXFEssenceElementHandler handle_essence_element;
+ gpointer mapping_data;
+
+ GstTagList *tags;
+
+ guint current_material_component;
+ MXFMetadataGenericPackage *material_package;
+ MXFMetadataTrack *material_track;
+ MXFMetadataStructuralComponent *component;
+
+ MXFMetadataGenericPackage *source_package;
+ MXFMetadataTrack *source_track;
+
+ GstCaps *caps;
+} GstMXFPad;
+
+typedef struct
+{
+ GstPadClass parent;
+
+} GstMXFPadClass;
+
+G_DEFINE_TYPE (GstMXFPad, gst_mxf_pad, GST_TYPE_PAD);
+
+static void
+gst_mxf_pad_finalize (GObject * object)
+{
+ GstMXFPad *pad = GST_MXF_PAD (object);
+
+ gst_caps_replace (&pad->caps, NULL);
+
+ g_free (pad->mapping_data);
+ pad->mapping_data = NULL;
+
+ if (pad->tags) {
+ gst_tag_list_free (pad->tags);
+ pad->tags = NULL;
+ }
+
+ G_OBJECT_CLASS (gst_mxf_pad_parent_class)->finalize (object);
+}
+
+static void
+gst_mxf_pad_class_init (GstMXFPadClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->finalize = gst_mxf_pad_finalize;
+}
+
+static void
+gst_mxf_pad_init (GstMXFPad * pad)
+{
+
+}
+
+static gboolean gst_mxf_demux_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_mxf_demux_src_event (GstPad * pad, GstEvent * event);
+static const GstQueryType *gst_mxf_demux_src_query_type (GstPad * pad);
+static gboolean gst_mxf_demux_src_query (GstPad * pad, GstQuery * query);
+
+GST_BOILERPLATE (GstMXFDemux, gst_mxf_demux, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_mxf_demux_flush (GstMXFDemux * demux, gboolean discont)
+{
+ GST_DEBUG_OBJECT (demux, "flushing queued data in the MXF demuxer");
+
+ gst_adapter_clear (demux->adapter);
+
+ demux->flushing = FALSE;
+
+ /* Only in push mode */
+ if (!demux->random_access) {
+ /* We reset the offset and will get one from first push */
+ demux->offset = 0;
+ }
+}
+
+static void
+gst_mxf_demux_remove_pad (GstMXFPad * pad, GstMXFDemux * demux)
+{
+ gst_element_remove_pad (GST_ELEMENT (demux), GST_PAD (pad));
+}
+
+static void
+gst_mxf_demux_reset_mxf_state (GstMXFDemux * demux)
+{
+ GST_DEBUG_OBJECT (demux, "Resetting MXF state");
+ mxf_partition_pack_reset (&demux->partition);
+ mxf_primer_pack_reset (&demux->primer);
+}
+
+static void
+gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
+{
+ guint i;
+
+ GST_DEBUG_OBJECT (demux, "Resetting metadata");
+
+ demux->update_metadata = TRUE;
+ demux->final_metadata = FALSE;
+
+ demux->current_package = NULL;
+
+ mxf_metadata_preface_reset (&demux->preface);
+
+ if (demux->identification) {
+ for (i = 0; i < demux->identification->len; i++)
+ mxf_metadata_identification_reset (&g_array_index (demux->identification,
+ MXFMetadataIdentification, i));
+ g_array_free (demux->identification, TRUE);
+ demux->identification = NULL;
+ }
+
+ mxf_metadata_content_storage_reset (&demux->content_storage);
+
+ if (demux->essence_container_data) {
+ for (i = 0; i < demux->essence_container_data->len; i++)
+ mxf_metadata_essence_container_data_reset (&g_array_index
+ (demux->essence_container_data, MXFMetadataEssenceContainerData, i));
+ g_array_free (demux->essence_container_data, TRUE);
+ demux->essence_container_data = NULL;
+ }
+
+ if (demux->material_package) {
+ for (i = 0; i < demux->material_package->len; i++)
+ mxf_metadata_generic_package_reset (&g_array_index
+ (demux->material_package, MXFMetadataGenericPackage, i));
+ g_array_free (demux->material_package, TRUE);
+ demux->material_package = NULL;
+ }
+
+ if (demux->source_package) {
+ for (i = 0; i < demux->source_package->len; i++)
+ mxf_metadata_generic_package_reset (&g_array_index (demux->source_package,
+ MXFMetadataGenericPackage, i));
+ g_array_free (demux->source_package, TRUE);
+ demux->source_package = NULL;
+ }
+
+ if (demux->package) {
+ g_ptr_array_free (demux->package, TRUE);
+ demux->package = NULL;
+ }
+
+ if (demux->track) {
+ for (i = 0; i < demux->track->len; i++)
+ mxf_metadata_track_reset (&g_array_index (demux->track,
+ MXFMetadataTrack, i));
+ g_array_free (demux->track, TRUE);
+ demux->track = NULL;
+ }
+
+ if (demux->sequence) {
+ for (i = 0; i < demux->sequence->len; i++)
+ mxf_metadata_sequence_reset (&g_array_index (demux->sequence,
+ MXFMetadataSequence, i));
+ g_array_free (demux->sequence, TRUE);
+ demux->sequence = NULL;
+ }
+
+ if (demux->structural_component) {
+ for (i = 0; i < demux->structural_component->len; i++)
+ mxf_metadata_structural_component_reset (&g_array_index
+ (demux->structural_component, MXFMetadataStructuralComponent, i));
+ g_array_free (demux->structural_component, TRUE);
+ demux->structural_component = NULL;
+ }
+
+ if (demux->generic_descriptor) {
+ for (i = 0; i < demux->generic_descriptor->len; i++)
+ mxf_metadata_generic_descriptor_reset (&g_array_index
+ (demux->generic_descriptor, MXFMetadataGenericDescriptor, i));
+ g_array_free (demux->generic_descriptor, TRUE);
+ demux->generic_descriptor = NULL;
+ }
+
+ if (demux->file_descriptor) {
+ for (i = 0; i < demux->file_descriptor->len; i++)
+ mxf_metadata_file_descriptor_reset (&g_array_index
+ (demux->file_descriptor, MXFMetadataFileDescriptor, i));
+ g_array_free (demux->file_descriptor, TRUE);
+ demux->file_descriptor = NULL;
+ }
+
+ if (demux->multiple_descriptor) {
+ for (i = 0; i < demux->multiple_descriptor->len; i++)
+ mxf_metadata_multiple_descriptor_reset (&g_array_index
+ (demux->multiple_descriptor, MXFMetadataMultipleDescriptor, i));
+ g_array_free (demux->multiple_descriptor, TRUE);
+ demux->multiple_descriptor = NULL;
+ }
+
+ if (demux->generic_picture_essence_descriptor) {
+ for (i = 0; i < demux->generic_picture_essence_descriptor->len; i++)
+ mxf_metadata_generic_picture_essence_descriptor_reset (&g_array_index
+ (demux->generic_picture_essence_descriptor,
+ MXFMetadataGenericPictureEssenceDescriptor, i));
+ g_array_free (demux->generic_picture_essence_descriptor, TRUE);
+ demux->generic_picture_essence_descriptor = NULL;
+ }
+
+ if (demux->cdci_picture_essence_descriptor) {
+ for (i = 0; i < demux->cdci_picture_essence_descriptor->len; i++)
+ mxf_metadata_cdci_picture_essence_descriptor_reset (&g_array_index
+ (demux->cdci_picture_essence_descriptor,
+ MXFMetadataCDCIPictureEssenceDescriptor, i));
+ g_array_free (demux->cdci_picture_essence_descriptor, TRUE);
+ demux->cdci_picture_essence_descriptor = NULL;
+ }
+
+ if (demux->mpeg_video_descriptor) {
+ for (i = 0; i < demux->mpeg_video_descriptor->len; i++)
+ mxf_metadata_mpeg_video_descriptor_reset (&g_array_index
+ (demux->mpeg_video_descriptor, MXFMetadataMPEGVideoDescriptor, i));
+ g_array_free (demux->mpeg_video_descriptor, TRUE);
+ demux->mpeg_video_descriptor = NULL;
+ }
+
+ if (demux->generic_sound_essence_descriptor) {
+ for (i = 0; i < demux->generic_sound_essence_descriptor->len; i++)
+ mxf_metadata_generic_sound_essence_descriptor_reset (&g_array_index
+ (demux->generic_sound_essence_descriptor,
+ MXFMetadataGenericSoundEssenceDescriptor, i));
+ g_array_free (demux->generic_sound_essence_descriptor, TRUE);
+ demux->generic_sound_essence_descriptor = NULL;
+ }
+
+ if (demux->wave_audio_essence_descriptor) {
+ for (i = 0; i < demux->wave_audio_essence_descriptor->len; i++)
+ mxf_metadata_wave_audio_essence_descriptor_reset (&g_array_index
+ (demux->wave_audio_essence_descriptor,
+ MXFMetadataWaveAudioEssenceDescriptor, i));
+ g_array_free (demux->wave_audio_essence_descriptor, TRUE);
+ demux->wave_audio_essence_descriptor = NULL;
+ }
+
+ if (demux->descriptor) {
+ g_ptr_array_free (demux->descriptor, TRUE);
+ demux->descriptor = NULL;
+ }
+
+ if (demux->locator) {
+ for (i = 0; i < demux->locator->len; i++)
+ mxf_metadata_locator_reset (&g_array_index (demux->locator,
+ MXFMetadataLocator, i));
+ g_array_free (demux->locator, TRUE);
+ demux->locator = NULL;
+ }
+}
+
+static void
+gst_mxf_demux_reset (GstMXFDemux * demux)
+{
+ GST_DEBUG_OBJECT (demux, "cleaning up MXF demuxer");
+
+ demux->flushing = FALSE;
+
+ demux->header_partition_pack_offset = 0;
+ demux->footer_partition_pack_offset = 0;
+ demux->offset = 0;
+
+ demux->run_in = -1;
+
+ memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
+
+ if (demux->new_seg_event) {
+ gst_event_unref (demux->new_seg_event);
+ demux->new_seg_event = NULL;
+ }
+
+ if (demux->close_seg_event) {
+ gst_event_unref (demux->close_seg_event);
+ demux->close_seg_event = NULL;
+ }
+
+ gst_adapter_clear (demux->adapter);
+
+ if (demux->src) {
+ g_ptr_array_foreach (demux->src, (GFunc) gst_mxf_demux_remove_pad, demux);
+ g_ptr_array_foreach (demux->src, (GFunc) gst_object_unref, NULL);
+ g_ptr_array_free (demux->src, TRUE);
+ demux->src = NULL;
+ }
+
+ gst_mxf_demux_reset_mxf_state (demux);
+ gst_mxf_demux_reset_metadata (demux);
+}
+
+static GstFlowReturn
+gst_mxf_demux_pull_range (GstMXFDemux * demux, guint64 offset,
+ guint size, GstBuffer ** buffer)
+{
+ GstFlowReturn ret;
+
+ ret = gst_pad_pull_range (demux->sinkpad, offset, size, buffer);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ GST_WARNING_OBJECT (demux,
+ "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
+ size, offset, gst_flow_get_name (ret));
+ *buffer = NULL;
+ return ret;
+ }
+
+ if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
+ GST_WARNING_OBJECT (demux,
+ "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
+ GST_BUFFER_SIZE (*buffer), size, offset);
+ gst_buffer_unref (*buffer);
+ ret = GST_FLOW_UNEXPECTED;
+ *buffer = NULL;
+ return ret;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_mxf_demux_push_src_event (GstMXFDemux * demux, GstEvent * event)
+{
+ gboolean ret = TRUE;
+ gint i;
+
+ GST_DEBUG_OBJECT (demux, "Pushing '%s' event downstream",
+ GST_EVENT_TYPE_NAME (event));
+
+ if (!demux->src)
+ return ret;
+
+ for (i = 0; i < demux->src->len; i++) {
+ GstPad *pad = GST_PAD (g_ptr_array_index (demux->src, i));
+
+ ret |= gst_pad_push_event (pad, gst_event_ref (event));
+ }
+
+ gst_event_unref (event);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_partition_pack (GstMXFDemux * demux, const MXFUL * key,
+ GstBuffer * buffer)
+{
+ if (demux->partition.valid) {
+ mxf_partition_pack_reset (&demux->partition);
+ mxf_primer_pack_reset (&demux->primer);
+ }
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling partition pack of size %u at offset %"
+ G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_partition_pack_parse (key, &demux->partition,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing partition pack failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (demux->partition.type == MXF_PARTITION_PACK_HEADER)
+ demux->footer_partition_pack_offset = demux->partition.footer_partition;
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_primer_pack (GstMXFDemux * demux, const MXFUL * key,
+ GstBuffer * buffer)
+{
+ GST_DEBUG_OBJECT (demux,
+ "Handling primer pack of size %u at offset %"
+ G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (G_UNLIKELY (!demux->partition.valid)) {
+ GST_ERROR_OBJECT (demux, "Primer pack before partition pack");
+ return GST_FLOW_ERROR;
+ }
+
+ if (G_UNLIKELY (demux->primer.valid)) {
+ GST_ERROR_OBJECT (demux, "Primer pack already exists");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!mxf_primer_pack_parse (key, &demux->primer,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing primer pack failed");
+ return GST_FLOW_ERROR;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_preface (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ MXFMetadataPreface preface;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata preface of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (demux->final_metadata) {
+ GST_DEBUG_OBJECT (demux, "Metadata is already final, skipping");
+ return GST_FLOW_OK;
+ }
+
+ if (!mxf_metadata_preface_parse (key, &preface, &demux->primer,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata preface failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (mxf_timestamp_is_unknown (&demux->preface.last_modified_date)
+ || (!mxf_timestamp_is_unknown (&preface.last_modified_date)
+ && mxf_timestamp_compare (&demux->preface.last_modified_date,
+ &preface.last_modified_date) < 0)) {
+ GST_DEBUG_OBJECT (demux,
+ "Timestamp of new preface is newer than old, updating metadata");
+ gst_mxf_demux_reset_metadata (demux);
+ memcpy (&demux->preface, &preface, sizeof (MXFMetadataPreface));
+ }
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_identification (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ MXFMetadataIdentification identification;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata identification of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_identification_parse (key, &identification,
+ &demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata identification failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->identification)
+ demux->identification =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataIdentification));
+
+ g_array_append_val (demux->identification, identification);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_content_storage (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata content storage of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_content_storage_parse (key,
+ &demux->content_storage, &demux->primer, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata content storage failed");
+ return GST_FLOW_ERROR;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_essence_container_data (GstMXFDemux *
+ demux, const MXFUL * key, GstBuffer * buffer)
+{
+ MXFMetadataEssenceContainerData essence_container_data;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata essence container data of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_essence_container_data_parse (key,
+ &essence_container_data, &demux->primer, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata essence container data failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->essence_container_data)
+ demux->essence_container_data =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataEssenceContainerData));
+
+ g_array_append_val (demux->essence_container_data, essence_container_data);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_material_package (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ MXFMetadataGenericPackage material_package;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata material package of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_generic_package_parse (key, &material_package,
+ &demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata material package failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->material_package)
+ demux->material_package =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataMaterialPackage));
+
+ g_array_append_val (demux->material_package, material_package);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_source_package (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ MXFMetadataGenericPackage source_package;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata source package of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_generic_package_parse (key, &source_package,
+ &demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata source package failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->source_package)
+ demux->source_package =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataSourcePackage));
+
+ g_array_append_val (demux->source_package, source_package);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_track (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ MXFMetadataTrack track;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata track of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_track_parse (key, &track, &demux->primer,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata track timecode failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->track)
+ demux->track = g_array_new (FALSE, FALSE, sizeof (MXFMetadataTrack));
+
+ g_array_append_val (demux->track, track);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_sequence (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ MXFMetadataSequence sequence;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata sequence of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_sequence_parse (key, &sequence,
+ &demux->primer, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata sequence failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->sequence)
+ demux->sequence = g_array_new (FALSE, FALSE, sizeof (MXFMetadataSequence));
+
+ g_array_append_val (demux->sequence, sequence);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_structural_component (GstMXFDemux * demux,
+ const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataStructuralComponent component;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata structural component of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!mxf_metadata_structural_component_parse (key, &component,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata structural component failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->structural_component)
+ demux->structural_component =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataStructuralComponent));
+
+ g_array_append_val (demux->structural_component, component);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_generic_descriptor (GstMXFDemux * demux,
+ const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataGenericDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata generic descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_generic_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata generic descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->generic_descriptor)
+ demux->generic_descriptor =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataGenericDescriptor));
+
+ g_array_append_val (demux->generic_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_file_descriptor (GstMXFDemux * demux,
+ const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataFileDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata file descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_file_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata file descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->file_descriptor)
+ demux->file_descriptor =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataFileDescriptor));
+
+ g_array_append_val (demux->file_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_multiple_descriptor (GstMXFDemux * demux,
+ const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataMultipleDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata multiple descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_multiple_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata multiple descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->multiple_descriptor)
+ demux->multiple_descriptor =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataMultipleDescriptor));
+
+ g_array_append_val (demux->multiple_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_generic_picture_essence_descriptor (GstMXFDemux *
+ demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataGenericPictureEssenceDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata generic picture essence descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux,
+ "Parsing metadata generic picture essence descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->generic_picture_essence_descriptor)
+ demux->generic_picture_essence_descriptor =
+ g_array_new (FALSE, FALSE,
+ sizeof (MXFMetadataGenericPictureEssenceDescriptor));
+
+ g_array_append_val (demux->generic_picture_essence_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_cdci_picture_essence_descriptor (GstMXFDemux *
+ demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataCDCIPictureEssenceDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata CDCI picture essence descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_cdci_picture_essence_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux,
+ "Parsing metadata CDCI picture essence descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->cdci_picture_essence_descriptor)
+ demux->cdci_picture_essence_descriptor =
+ g_array_new (FALSE, FALSE,
+ sizeof (MXFMetadataCDCIPictureEssenceDescriptor));
+
+ g_array_append_val (demux->cdci_picture_essence_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_mpeg_video_descriptor (GstMXFDemux * demux,
+ const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataMPEGVideoDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata MPEG video descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_mpeg_video_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata MPEG video descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->mpeg_video_descriptor)
+ demux->mpeg_video_descriptor =
+ g_array_new (FALSE, FALSE, sizeof (MXFMetadataMPEGVideoDescriptor));
+
+ g_array_append_val (demux->mpeg_video_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_generic_sound_essence_descriptor (GstMXFDemux *
+ demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataGenericSoundEssenceDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata generic sound essence descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_generic_sound_essence_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux,
+ "Parsing metadata generic sound essence descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->generic_sound_essence_descriptor)
+ demux->generic_sound_essence_descriptor =
+ g_array_new (FALSE, FALSE,
+ sizeof (MXFMetadataGenericSoundEssenceDescriptor));
+
+ g_array_append_val (demux->generic_sound_essence_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_wave_audio_essence_descriptor (GstMXFDemux *
+ demux, const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataWaveAudioEssenceDescriptor descriptor;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata wave sound essence descriptor of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_wave_audio_essence_descriptor_parse (key, &descriptor,
+ &demux->primer, type, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux,
+ "Parsing metadata wave sound essence descriptor failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->wave_audio_essence_descriptor)
+ demux->wave_audio_essence_descriptor =
+ g_array_new (FALSE, FALSE,
+ sizeof (MXFMetadataWaveAudioEssenceDescriptor));
+
+ g_array_append_val (demux->wave_audio_essence_descriptor, descriptor);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata_locator (GstMXFDemux * demux,
+ const MXFUL * key, guint16 type, GstBuffer * buffer)
+{
+ MXFMetadataLocator locator;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata locator of size %u"
+ " at offset %" G_GUINT64_FORMAT " with type 0x%04d",
+ GST_BUFFER_SIZE (buffer), demux->offset, type);
+
+ if (!mxf_metadata_locator_parse (key, &locator, &demux->primer,
+ type, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ GST_ERROR_OBJECT (demux, "Parsing metadata locator failed");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->locator)
+ demux->locator = g_array_new (FALSE, FALSE, sizeof (MXFMetadataLocator));
+
+ g_array_append_val (demux->locator, locator);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_header_metadata_resolve_references (GstMXFDemux * demux)
+{
+ guint i, j, k;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ GST_DEBUG_OBJECT (demux, "Resolve metadata references");
+ demux->update_metadata = FALSE;
+ if (demux->partition.closed && demux->partition.complete)
+ demux->final_metadata = TRUE;
+
+ /* Fill in demux->descriptor */
+ demux->descriptor = g_ptr_array_new ();
+ if (demux->generic_descriptor) {
+ for (i = 0; i < demux->generic_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->generic_descriptor,
+ MXFMetadataGenericDescriptor, i));
+ }
+ }
+ if (demux->file_descriptor) {
+ for (i = 0; i < demux->file_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->file_descriptor, MXFMetadataFileDescriptor,
+ i));
+ }
+ }
+ if (demux->generic_picture_essence_descriptor) {
+ for (i = 0; i < demux->generic_picture_essence_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->generic_picture_essence_descriptor,
+ MXFMetadataGenericPictureEssenceDescriptor, i));
+ }
+ }
+ if (demux->cdci_picture_essence_descriptor) {
+ for (i = 0; i < demux->cdci_picture_essence_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->cdci_picture_essence_descriptor,
+ MXFMetadataCDCIPictureEssenceDescriptor, i));
+ }
+ }
+ if (demux->mpeg_video_descriptor) {
+ for (i = 0; i < demux->mpeg_video_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->mpeg_video_descriptor,
+ MXFMetadataMPEGVideoDescriptor, i));
+ }
+ }
+ if (demux->generic_sound_essence_descriptor) {
+ for (i = 0; i < demux->generic_sound_essence_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->generic_sound_essence_descriptor,
+ MXFMetadataGenericSoundEssenceDescriptor, i));
+ }
+ }
+ if (demux->wave_audio_essence_descriptor) {
+ for (i = 0; i < demux->wave_audio_essence_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->wave_audio_essence_descriptor,
+ MXFMetadataWaveAudioEssenceDescriptor, i));
+ }
+ }
+ if (demux->multiple_descriptor) {
+ for (i = 0; i < demux->multiple_descriptor->len; i++) {
+ g_ptr_array_add (demux->descriptor,
+ &g_array_index (demux->multiple_descriptor,
+ MXFMetadataMultipleDescriptor, i));
+ }
+ }
+
+ /* Fill in demux->package */
+ demux->package = g_ptr_array_new ();
+ if (demux->material_package) {
+ for (i = 0; i < demux->material_package->len; i++) {
+ g_ptr_array_add (demux->package, &g_array_index (demux->material_package,
+ MXFMetadataGenericPackage, i));
+ }
+ }
+ if (demux->source_package) {
+ for (i = 0; i < demux->source_package->len; i++) {
+ g_ptr_array_add (demux->package, &g_array_index (demux->source_package,
+ MXFMetadataGenericPackage, i));
+ }
+ }
+
+ /* Multiple descriptor */
+ if (demux->multiple_descriptor && demux->descriptor) {
+ for (i = 0; i < demux->multiple_descriptor->len; i++) {
+ MXFMetadataMultipleDescriptor *d =
+ &g_array_index (demux->multiple_descriptor,
+ MXFMetadataMultipleDescriptor, i);
+
+ d->sub_descriptors =
+ g_new0 (MXFMetadataGenericDescriptor *, d->n_sub_descriptors);
+ for (j = 0; j < d->n_sub_descriptors; j++) {
+ for (k = 0; k < demux->descriptor->len; k++) {
+ MXFMetadataGenericDescriptor *e =
+ g_ptr_array_index (demux->descriptor, k);
+
+ if (mxf_ul_is_equal (&d->sub_descriptors_uids[j], &e->instance_uid)) {
+ d->sub_descriptors[j] = e;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* See SMPTE 377M 8.4 */
+
+ /* Preface */
+ if (demux->package) {
+ for (i = 0; i < demux->package->len; i++) {
+ MXFMetadataGenericPackage *package =
+ g_ptr_array_index (demux->package, i);
+
+ if (mxf_ul_is_equal (&demux->preface.primary_package_uid,
+ &package->instance_uid)) {
+ demux->preface.primary_package = package;
+ break;
+ }
+ }
+ }
+
+ demux->preface.identifications =
+ g_new0 (MXFMetadataIdentification *, demux->preface.n_identifications);
+ if (demux->identification) {
+ for (i = 0; i < demux->identification->len; i++) {
+ MXFMetadataIdentification *identification =
+ &g_array_index (demux->identification,
+ MXFMetadataIdentification, i);
+
+ for (j = 0; j < demux->preface.n_identifications; j++) {
+ if (mxf_ul_is_equal (&demux->preface.identifications_uids[j],
+ &identification->instance_uid)) {
+ demux->preface.identifications[j] = identification;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!mxf_ul_is_equal (&demux->preface.content_storage_uid,
+ &demux->content_storage.instance_uid)) {
+ GST_ERROR_OBJECT (demux,
+ "Preface content storage UID not equal to actual content storage instance uid");
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
+ demux->preface.content_storage = &demux->content_storage;
+
+ /* TODO: dm_schemes */
+
+ /* Content storage */
+ demux->content_storage.packages =
+ g_new0 (MXFMetadataGenericPackage *, demux->content_storage.n_packages);
+ if (demux->package) {
+ for (i = 0; i < demux->package->len; i++) {
+ MXFMetadataGenericPackage *package =
+ g_ptr_array_index (demux->package, i);
+
+ for (j = 0; j < demux->content_storage.n_packages; j++) {
+ if (mxf_ul_is_equal (&demux->content_storage.packages_uids[j],
+ &package->instance_uid)) {
+ demux->content_storage.packages[j] = package;
+ break;
+ }
+ }
+ }
+ }
+
+ demux->content_storage.essence_container_data =
+ g_new0 (MXFMetadataEssenceContainerData *,
+ demux->content_storage.n_essence_container_data);
+ if (demux->essence_container_data) {
+ for (i = 0; i < demux->essence_container_data->len; i++) {
+ MXFMetadataEssenceContainerData *data =
+ &g_array_index (demux->essence_container_data,
+ MXFMetadataEssenceContainerData, i);
+
+ for (j = 0; j < demux->content_storage.n_essence_container_data; j++) {
+ if (mxf_ul_is_equal (&demux->
+ content_storage.essence_container_data_uids[j],
+ &data->instance_uid)) {
+ demux->content_storage.essence_container_data[j] = data;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Essence container data */
+ if (demux->package && demux->essence_container_data) {
+ for (i = 0; i < demux->package->len; i++) {
+ MXFMetadataGenericPackage *package =
+ g_ptr_array_index (demux->package, i);
+
+ for (j = 0; j < demux->essence_container_data->len; j++) {
+ MXFMetadataEssenceContainerData *data =
+ &g_array_index (demux->essence_container_data,
+ MXFMetadataEssenceContainerData, j);
+
+ if (mxf_umid_is_equal (&data->linked_package_uid,
+ &package->package_uid)) {
+ data->linked_package = package;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Generic package */
+ if (demux->package) {
+ for (i = 0; i < demux->package->len; i++) {
+ MXFMetadataGenericPackage *package =
+ g_ptr_array_index (demux->package, i);
+
+ package->tracks = g_new0 (MXFMetadataTrack *, package->n_tracks);
+ if (demux->track) {
+ for (j = 0; j < package->n_tracks; j++) {
+ for (k = 0; k < demux->track->len; k++) {
+ MXFMetadataTrack *track =
+ &g_array_index (demux->track, MXFMetadataTrack, k);
+
+ if (mxf_ul_is_equal (&package->tracks_uids[j],
+ &track->instance_uid)) {
+ package->tracks[j] = track;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Resolve descriptors */
+ if (package->n_descriptors > 0 && demux->descriptor) {
+ MXFMetadataGenericDescriptor *d = NULL;
+
+ for (j = 0; j < demux->descriptor->len; j++) {
+ MXFMetadataGenericDescriptor *descriptor =
+ g_ptr_array_index (demux->descriptor, j);
+
+ if (mxf_ul_is_equal (&package->descriptors_uid,
+ &descriptor->instance_uid)) {
+ d = descriptor;
+ break;
+ }
+ }
+
+ if (d && d->type == MXF_METADATA_MULTIPLE_DESCRIPTOR) {
+ MXFMetadataMultipleDescriptor *e =
+ (MXFMetadataMultipleDescriptor *) d;
+
+ package->n_descriptors = e->n_sub_descriptors;
+ package->descriptors =
+ g_new0 (MXFMetadataGenericDescriptor *, e->n_sub_descriptors);
+
+ /* These are already resolved */
+ for (j = 0; j < e->n_sub_descriptors; j++)
+ package->descriptors[j] = e->sub_descriptors[j];
+ } else {
+ package->n_descriptors = 1;
+ package->descriptors = g_new0 (MXFMetadataGenericDescriptor *, 1);
+ package->descriptors[0] = d;
+ }
+ }
+
+ if (package->tracks && package->descriptors) {
+ for (j = 0; j < package->n_tracks; j++) {
+ MXFMetadataTrack *track = package->tracks[j];
+ guint n_descriptor = 0;
+
+ if (!track)
+ continue;
+
+ for (k = 0; k < package->n_descriptors; k++) {
+ MXFMetadataGenericDescriptor *d = package->descriptors[k];
+ MXFMetadataFileDescriptor *e;
+
+ if (!d || !d->is_file_descriptor)
+ continue;
+
+ e = (MXFMetadataFileDescriptor *) d;
+
+ if (e->linked_track_id == track->track_id)
+ n_descriptor++;
+ }
+
+ track->n_descriptor = n_descriptor;
+ track->descriptor =
+ g_new0 (MXFMetadataFileDescriptor *, n_descriptor);
+ n_descriptor = 0;
+
+ for (k = 0; k < package->n_descriptors; k++) {
+ MXFMetadataGenericDescriptor *d = package->descriptors[k];
+ MXFMetadataFileDescriptor *e;
+
+ if (!d || !d->is_file_descriptor)
+ continue;
+
+ e = (MXFMetadataFileDescriptor *) d;
+
+ if (e->linked_track_id == track->track_id)
+ track->descriptor[n_descriptor++] = e;
+ }
+ }
+ }
+ }
+ }
+
+ /* Tracks */
+ if (demux->track && demux->sequence) {
+ for (i = 0; i < demux->track->len; i++) {
+ MXFMetadataTrack *track =
+ &g_array_index (demux->track, MXFMetadataTrack, i);
+
+ for (j = 0; j < demux->sequence->len; j++) {
+ MXFMetadataSequence *sequence =
+ &g_array_index (demux->sequence, MXFMetadataSequence,
+ i);
+
+ if (mxf_ul_is_equal (&track->sequence_uid, &sequence->instance_uid)) {
+ track->sequence = sequence;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Sequences */
+ if (demux->sequence) {
+ for (i = 0; i < demux->sequence->len; i++) {
+ MXFMetadataSequence *sequence =
+ &g_array_index (demux->sequence, MXFMetadataSequence, i);
+
+ sequence->structural_components =
+ g_new0 (MXFMetadataStructuralComponent *,
+ sequence->n_structural_components);
+
+ if (demux->structural_component) {
+ for (j = 0; j < sequence->n_structural_components; j++) {
+ for (k = 0; k < demux->structural_component->len; k++) {
+ MXFMetadataStructuralComponent *component =
+ &g_array_index (demux->structural_component,
+ MXFMetadataStructuralComponent, k);
+
+ if (mxf_ul_is_equal (&sequence->structural_components_uids[j],
+ &component->instance_uid)) {
+ sequence->structural_components[j] = component;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Source clips */
+ if (demux->structural_component && demux->source_package) {
+ for (i = 0; i < demux->structural_component->len; i++) {
+ MXFMetadataStructuralComponent *component =
+ &g_array_index (demux->structural_component,
+ MXFMetadataStructuralComponent, i);
+
+ if (component->type != MXF_METADATA_SOURCE_CLIP)
+ continue;
+
+ for (j = 0; j < demux->source_package->len; j++) {
+ MXFMetadataGenericPackage *package =
+ &g_array_index (demux->source_package, MXFMetadataGenericPackage,
+ j);
+
+ if (mxf_umid_is_equal (&component->source_clip.source_package_id,
+ &package->package_uid)) {
+ component->source_clip.source_package = package;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Generic descriptors */
+ if (demux->descriptor) {
+ for (i = 0; i < demux->descriptor->len; i++) {
+ MXFMetadataGenericDescriptor *descriptor =
+ g_ptr_array_index (demux->descriptor, i);
+
+ descriptor->locators =
+ g_new0 (MXFMetadataLocator *, descriptor->n_locators);
+
+ if (demux->locator) {
+ for (j = 0; j < descriptor->n_locators; j++) {
+ for (k = 0; k < demux->locator->len; k++) {
+ MXFMetadataLocator *locator =
+ &g_array_index (demux->locator, MXFMetadataLocator,
+ k);
+
+ if (mxf_ul_is_equal (&descriptor->locators_uids[j],
+ &locator->instance_uid)) {
+ descriptor->locators[j] = locator;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Mark packages as material, top-level source and source */
+ if (demux->material_package) {
+ for (i = 0; i < demux->material_package->len; i++) {
+ MXFMetadataGenericPackage *package =
+ &g_array_index (demux->material_package, MXFMetadataGenericPackage,
+ i);
+
+ package->type = MXF_METADATA_GENERIC_PACKAGE_MATERIAL;
+
+ for (j = 0; j < package->n_tracks; j++) {
+ MXFMetadataTrack *track = package->tracks[j];
+ MXFMetadataSequence *sequence;
+
+ if (!track || !track->sequence)
+ continue;
+
+ sequence = track->sequence;
+
+ for (k = 0; k < sequence->n_structural_components; k++) {
+ MXFMetadataStructuralComponent *component =
+ sequence->structural_components[k];
+
+ if (!component || component->type != MXF_METADATA_SOURCE_CLIP
+ || !component->source_clip.source_package)
+ continue;
+
+ component->source_clip.source_package->type =
+ MXF_METADATA_GENERIC_PACKAGE_TOP_LEVEL_SOURCE;
+ }
+ }
+ }
+ }
+
+ /* Store, for every package, the number of timestamp, metadata, essence and other tracks */
+ if (demux->package) {
+ for (i = 0; i < demux->package->len; i++) {
+ MXFMetadataGenericPackage *package =
+ g_ptr_array_index (demux->package, i);
+
+ if (!package->tracks || package->n_tracks == 0)
+ continue;
+
+ for (j = 0; j < package->n_tracks; j++) {
+ MXFMetadataTrack *track = package->tracks[j];
+ MXFMetadataSequence *sequence;
+ MXFMetadataTrackType type = MXF_METADATA_TRACK_UNKNOWN;
+
+ if (!track || !track->sequence)
+ continue;
+
+ sequence = track->sequence;
+
+ if (mxf_ul_is_zero (&sequence->data_definition)
+ && sequence->structural_components) {
+ for (k = 0; k < sequence->n_structural_components; k++) {
+ MXFMetadataStructuralComponent *component =
+ sequence->structural_components[k];
+ if (!component || mxf_ul_is_zero (&component->data_definition))
+ continue;
+
+ type =
+ mxf_metadata_track_identifier_parse (&component->
+ data_definition);
+ break;
+ }
+ } else {
+ type =
+ mxf_metadata_track_identifier_parse (&sequence->data_definition);
+ }
+
+ if (type == MXF_METADATA_TRACK_UNKNOWN)
+ continue;
+ else if ((type & 0xf0) == 0x10)
+ package->n_timecode_tracks++;
+ else if ((type & 0xf0) == 0x20)
+ package->n_metadata_tracks++;
+ else if ((type & 0xf0) == 0x30)
+ package->n_essence_tracks++;
+ else if ((type & 0xf0) == 0x40)
+ package->n_other_tracks++;
+ }
+ }
+ }
+
+ return ret;
+
+error:
+ return ret;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_header_metadata_update_streams (GstMXFDemux * demux)
+{
+ MXFMetadataGenericPackage *current_package = NULL;
+ guint i, j, k;
+ gboolean first_run;
+
+ GST_DEBUG_OBJECT (demux, "Updating streams");
+
+choose_package:
+ /* If no package was selected, select the first material package */
+ if (mxf_umid_is_zero (&demux->current_package_uid)
+ && !demux->material_package) {
+ GST_ERROR_OBJECT (demux, "No material package");
+ return GST_FLOW_ERROR;
+ } else if (mxf_umid_is_zero (&demux->current_package_uid)) {
+ MXFMetadataGenericPackage *p =
+ (MXFMetadataGenericPackage *) demux->material_package->data;
+ memcpy (&demux->current_package_uid, &p->package_uid, 32);
+ current_package = p;
+ if (demux->src) {
+ for (i = 0; i < demux->src->len; i++) {
+ GstMXFPad *pad = g_ptr_array_index (demux->src, i);
+ gst_element_remove_pad (GST_ELEMENT_CAST (demux), GST_PAD_CAST (pad));
+ gst_object_unref (pad);
+ }
+ g_ptr_array_free (demux->src, TRUE);
+ demux->src = NULL;
+ }
+ }
+
+ if (!current_package && demux->package) {
+ for (i = 0; i < demux->package->len; i++) {
+ MXFMetadataGenericPackage *p = g_ptr_array_index (demux->package, i);
+
+ if (mxf_umid_is_equal (&p->package_uid, &demux->current_package_uid)) {
+ current_package = p;
+ break;
+ }
+ }
+ }
+
+ if (!current_package) {
+ GST_WARNING_OBJECT (demux,
+ "Selected package not found in header metadata, choosing the first best");
+ memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
+ goto choose_package;
+ }
+
+ if (current_package->type == MXF_METADATA_GENERIC_PACKAGE_SOURCE) {
+ GST_WARNING_OBJECT (demux,
+ "Selected package is not a material package or top-level source package, choosing the first best");
+ memset (&demux->current_package_uid, 0, sizeof (MXFUMID));
+ goto choose_package;
+ }
+
+ if (!current_package->tracks) {
+ GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks");
+ return GST_FLOW_ERROR;
+ } else if (!current_package->n_essence_tracks) {
+ GST_ERROR_OBJECT (demux, "Current package has no essence tracks");
+ return GST_FLOW_ERROR;
+ }
+
+ first_run = (demux->src == NULL);
+ demux->current_package = current_package;
+
+ for (i = 0; i < current_package->n_tracks; i++) {
+ MXFMetadataTrack *track = current_package->tracks[i];
+ MXFMetadataTrackType track_type = MXF_METADATA_TRACK_UNKNOWN;
+ MXFMetadataSequence *sequence;
+ MXFMetadataStructuralComponent *component = NULL;
+ MXFMetadataGenericPackage *source_package = NULL;
+ MXFMetadataTrack *source_track = NULL;
+ GstMXFPad *pad = NULL;
+ GstCaps *caps = NULL;
+
+ GST_DEBUG_OBJECT (demux, "Handling track %d", i);
+
+ if (!track) {
+ GST_WARNING_OBJECT (demux, "Unresolved track");
+ continue;
+ } else if (!track->sequence) {
+ GST_WARNING_OBJECT (demux, "Track with no sequence");
+ continue;
+ }
+
+ sequence = track->sequence;
+
+ if (current_package->type == MXF_METADATA_GENERIC_PACKAGE_TOP_LEVEL_SOURCE) {
+ source_package = current_package;
+ source_track = track;
+ }
+
+ track_type =
+ mxf_metadata_track_identifier_parse (&sequence->data_definition);
+
+ /* TODO: handle multiple components, see SMPTE 377M page 37 */
+ if (sequence->structural_components && sequence->structural_components[0]) {
+ component = sequence->structural_components[0];
+
+ if (track_type == MXF_METADATA_TRACK_UNKNOWN)
+ track_type =
+ mxf_metadata_track_identifier_parse (&component->data_definition);
+
+ if (!source_package && component->type == MXF_METADATA_SOURCE_CLIP
+ && component->source_clip.source_package
+ && component->source_clip.source_package->type ==
+ MXF_METADATA_GENERIC_PACKAGE_TOP_LEVEL_SOURCE
+ && component->source_clip.source_package->tracks) {
+ source_package = component->source_clip.source_package;
+
+ for (k = 0; k < source_package->n_tracks; k++) {
+ MXFMetadataTrack *tmp = source_package->tracks[k];
+
+ if (tmp->track_id == component->source_clip.source_track_id) {
+ source_track = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ if (track_type && (track_type & 0xf0) != 0x30) {
+ GST_DEBUG_OBJECT (demux, "No essence track");
+ continue;
+ }
+
+ if (!source_package || track_type == MXF_METADATA_TRACK_UNKNOWN
+ || !source_track || !component) {
+ GST_WARNING_OBJECT (demux,
+ "No source package or track type for track found");
+ continue;
+ }
+
+ if (!source_package->descriptors) {
+ GST_WARNING_OBJECT (demux, "Source package has no descriptors");
+ continue;
+ }
+
+ if (!source_track->descriptor) {
+ GST_WARNING_OBJECT (demux, "No descriptor found for track");
+ continue;
+ }
+
+ if (demux->src && demux->src->len > 0) {
+ /* Find pad from track_id */
+ for (j = 0; j < demux->src->len; j++) {
+ GstMXFPad *tmp = g_ptr_array_index (demux->src, j);
+
+ if (tmp->track_id == track->track_id) {
+ pad = tmp;
+ break;
+ }
+ }
+ }
+
+ if (!pad && first_run) {
+ GstPadTemplate *templ;
+ gchar *pad_name;
+
+ switch (track_type) {
+ case MXF_METADATA_TRACK_PICTURE_ESSENCE:
+ templ =
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
+ "video_%d");
+ pad_name = g_strdup_printf ("video_%d", source_track->track_id);
+ break;
+ case MXF_METADATA_TRACK_SOUND_ESSENCE:
+ templ =
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
+ "audio_%d");
+ pad_name = g_strdup_printf ("audio_%d", source_track->track_id);
+ break;
+ case MXF_METADATA_TRACK_DATA_ESSENCE:
+ templ =
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demux),
+ "data_%d");
+ pad_name = g_strdup_printf ("data_%d", source_track->track_id);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_assert (templ != NULL);
+
+ /* Create pad */
+ pad = (GstMXFPad *) g_object_new (GST_TYPE_MXF_PAD,
+ "name", pad_name, "direction", GST_PAD_SRC, "template", templ, NULL);
+ pad->need_segment = TRUE;
+ g_free (pad_name);
+ }
+
+ if (!pad) {
+ GST_WARNING_OBJECT (demux,
+ "Not the first pad addition run, ignoring new track");
+ continue;
+ }
+
+ /* Update pad */
+ pad->track_id = track->track_id;
+ pad->track_type = track_type;
+
+ pad->material_package = current_package;
+ pad->material_track = track;
+ pad->current_material_component = 0;
+ pad->component = component;
+
+ pad->source_package = source_package;
+ pad->source_track = source_track;
+
+ pad->handle_essence_element = NULL;
+ g_free (pad->mapping_data);
+ pad->mapping_data = NULL;
+
+ switch (track_type) {
+ case MXF_METADATA_TRACK_PICTURE_ESSENCE:
+ if (mxf_is_mpeg_video_essence_track (source_track))
+ caps =
+ mxf_mpeg_video_create_caps (source_package, source_track,
+ &pad->tags, &pad->handle_essence_element, &pad->mapping_data);
+ break;
+ case MXF_METADATA_TRACK_SOUND_ESSENCE:
+ if (mxf_is_aes_bwf_essence_track (source_track))
+ caps =
+ mxf_aes_bwf_create_caps (source_package, source_track, &pad->tags,
+ &pad->handle_essence_element, &pad->mapping_data);
+ break;
+ case MXF_METADATA_TRACK_DATA_ESSENCE:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (!caps) {
+ GST_WARNING_OBJECT (demux, "No caps created, ignoring stream");
+ gst_object_unref (pad);
+ continue;
+ }
+
+ GST_DEBUG_OBJECT (demux, "Created caps %" GST_PTR_FORMAT, caps);
+
+ if (pad->caps && !gst_caps_is_equal (pad->caps, caps)) {
+ gst_pad_set_caps (GST_PAD_CAST (pad), caps);
+ gst_caps_replace (&pad->caps, gst_caps_ref (caps));
+ } else if (!pad->caps) {
+ gst_pad_set_caps (GST_PAD_CAST (pad), caps);
+ pad->caps = gst_caps_ref (caps);
+
+ gst_pad_set_event_function (GST_PAD_CAST (pad),
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_src_event));
+
+ gst_pad_set_query_type_function (GST_PAD_CAST (pad),
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query_type));
+ gst_pad_set_query_function (GST_PAD_CAST (pad),
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_src_query));
+
+ gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
+ gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
+
+ gst_element_add_pad (GST_ELEMENT_CAST (demux), gst_object_ref (pad));
+
+ if (!demux->src)
+ demux->src = g_ptr_array_new ();
+ g_ptr_array_add (demux->src, pad);
+ }
+ gst_caps_unref (caps);
+ }
+
+ gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_metadata (GstMXFDemux * demux, const MXFUL * key,
+ GstBuffer * buffer)
+{
+ guint16 type;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ type = GST_READ_UINT16_BE (key->u + 13);
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling metadata of size %u at offset %"
+ G_GUINT64_FORMAT " of type 0x%04d", GST_BUFFER_SIZE (buffer),
+ demux->offset, type);
+
+ if (G_UNLIKELY (!demux->partition.valid)) {
+ GST_ERROR_OBJECT (demux, "Partition pack doesn't exist");
+ return GST_FLOW_ERROR;
+ }
+
+ if (G_UNLIKELY (!demux->primer.valid)) {
+ GST_ERROR_OBJECT (demux, "Primer pack doesn't exists");
+ return GST_FLOW_ERROR;
+ }
+
+ if (type != MXF_METADATA_PREFACE && !demux->update_metadata) {
+ GST_DEBUG_OBJECT (demux,
+ "Skipping parsing of metadata because it's older than what we have");
+ return GST_FLOW_OK;
+ }
+
+ /* Make writable as the parsing of descriptors sets already read local tags to 0x0000 */
+ if (!gst_buffer_is_writable (buffer))
+ buffer = gst_buffer_copy (buffer);
+ else
+ buffer = gst_buffer_ref (buffer);
+
+ switch (type) {
+ case MXF_METADATA_PREFACE:
+ ret = gst_mxf_demux_handle_metadata_preface (demux, key, buffer);
+ break;
+ case MXF_METADATA_IDENTIFICATION:
+ ret = gst_mxf_demux_handle_metadata_identification (demux, key, buffer);
+ break;
+ case MXF_METADATA_CONTENT_STORAGE:
+ ret = gst_mxf_demux_handle_metadata_content_storage (demux, key, buffer);
+ break;
+ case MXF_METADATA_ESSENCE_CONTAINER_DATA:
+ ret =
+ gst_mxf_demux_handle_metadata_essence_container_data (demux,
+ key, buffer);
+ break;
+ case MXF_METADATA_MATERIAL_PACKAGE:
+ ret = gst_mxf_demux_handle_metadata_material_package (demux, key, buffer);
+ break;
+ case MXF_METADATA_SOURCE_PACKAGE:
+ ret = gst_mxf_demux_handle_metadata_source_package (demux, key, buffer);
+ break;
+ case MXF_METADATA_TRACK:
+ ret = gst_mxf_demux_handle_metadata_track (demux, key, buffer);
+ break;
+ case MXF_METADATA_SEQUENCE:
+ ret = gst_mxf_demux_handle_metadata_sequence (demux, key, buffer);
+ break;
+ case MXF_METADATA_TIMECODE_COMPONENT:
+ case MXF_METADATA_SOURCE_CLIP:
+ ret =
+ gst_mxf_demux_handle_metadata_structural_component (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR:
+ case MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_generic_descriptor (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_FILE_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_file_descriptor (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_generic_picture_essence_descriptor
+ (demux, key, type, buffer);
+ break;
+ case MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_cdci_picture_essence_descriptor (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_MPEG_VIDEO_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_mpeg_video_descriptor (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_generic_sound_essence_descriptor (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_MULTIPLE_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_multiple_descriptor (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_WAVE_AUDIO_ESSENCE_DESCRIPTOR:
+ ret =
+ gst_mxf_demux_handle_metadata_wave_audio_essence_descriptor (demux,
+ key, type, buffer);
+ break;
+ case MXF_METADATA_NETWORK_LOCATOR:
+ case MXF_METADATA_TEXT_LOCATOR:
+ ret = gst_mxf_demux_handle_metadata_locator (demux, key, type, buffer);
+ break;
+ default:
+ GST_WARNING_OBJECT (demux,
+ "Unknown or unhandled metadata type 0x%04x", type);
+ break;
+ }
+
+ gst_buffer_unref (buffer);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_generic_container_system_item (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ GST_DEBUG_OBJECT (demux,
+ "Handling generic container system item of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ /* TODO: parse this */
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_generic_container_essence_element (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint32 track_number;
+ guint i;
+ GstMXFPad *pad = NULL;
+ GstBuffer *inbuf;
+ GstBuffer *outbuf = NULL;
+
+ GST_DEBUG_OBJECT (demux,
+ "Handling generic container essence element of size %u"
+ " at offset %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ if (!demux->current_package) {
+ GST_ERROR_OBJECT (demux, "No package selected yet");
+ return GST_FLOW_ERROR;
+ }
+
+ if (!demux->src || demux->src->len == 0) {
+ GST_ERROR_OBJECT (demux, "No streams created yet");
+ return GST_FLOW_ERROR;
+ }
+
+ track_number = GST_READ_UINT32_BE (&key->u[12]);
+
+ for (i = 0; i < demux->src->len; i++) {
+ GstMXFPad *p = g_ptr_array_index (demux->src, i);
+
+ if (p->source_track->track_number == track_number ||
+ (p->source_track->track_number == 0 &&
+ demux->src->len == 1 &&
+ demux->current_package->n_essence_tracks == 1)) {
+ pad = p;
+ break;
+ }
+ }
+
+ if (!pad) {
+ GST_WARNING_OBJECT (demux, "No corresponding pad found");
+ return GST_FLOW_OK;
+ }
+
+ /* TODO: Use a better start value */
+ if (pad->need_segment) {
+ gst_pad_push_event (GST_PAD_CAST (pad),
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
+ pad->need_segment = FALSE;
+ }
+
+ /* Create subbuffer to be able to change metadata */
+ inbuf = gst_buffer_create_sub (buffer, 0, GST_BUFFER_SIZE (buffer));
+
+ GST_BUFFER_TIMESTAMP (inbuf) =
+ gst_util_uint64_scale (pad->essence_element_count +
+ pad->material_track->origin,
+ GST_SECOND * pad->material_track->edit_rate.d,
+ pad->material_track->edit_rate.n);
+ GST_BUFFER_DURATION (inbuf) =
+ gst_util_uint64_scale (GST_SECOND, pad->material_track->edit_rate.d,
+ pad->material_track->edit_rate.n);
+ GST_BUFFER_OFFSET (inbuf) = pad->essence_element_count;
+ GST_BUFFER_OFFSET_END (inbuf) = GST_BUFFER_OFFSET_NONE;
+ gst_buffer_set_caps (inbuf, pad->caps);
+
+ if (pad->handle_essence_element) {
+ /* Takes ownership of inbuf */
+ ret =
+ pad->handle_essence_element (key, inbuf, pad->caps, pad->source_package,
+ pad->source_track, pad->component, pad->mapping_data, &outbuf);
+ inbuf = NULL;
+ } else {
+ outbuf = inbuf;
+ inbuf = NULL;
+ ret = GST_FLOW_OK;
+ }
+
+ pad->essence_element_count++;
+
+ if (ret != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (demux, "Failed to handle essence element");
+ if (outbuf) {
+ gst_buffer_unref (outbuf);
+ outbuf = NULL;
+ }
+ }
+
+ if (outbuf) {
+ ret = gst_pad_push (GST_PAD_CAST (pad), outbuf);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_random_index_pack (GstMXFDemux * demux, const MXFUL * key,
+ GstBuffer * buffer)
+{
+ GST_DEBUG_OBJECT (demux,
+ "Handling random index pack of size %u at offset %"
+ G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ /* TODO: Parse this */
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_index_table_segment (GstMXFDemux * demux,
+ const MXFUL * key, GstBuffer * buffer)
+{
+ GST_DEBUG_OBJECT (demux,
+ "Handling index table segment of size %u at offset %"
+ G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+
+ /* TODO: Parse this */
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mxf_demux_pull_klv_packet (GstMXFDemux * demux, guint64 offset, MXFUL * key,
+ GstBuffer ** outbuf, guint64 * read)
+{
+ GstBuffer *buffer = NULL;
+ const guint8 *data;
+ guint64 data_offset = 0;
+ guint64 length;
+ gchar key_str[48];
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ memset (key, 0, sizeof (MXFUL));
+
+ /* Pull 16 byte key and first byte of BER encoded length */
+ if ((ret =
+ gst_mxf_demux_pull_range (demux, offset, 17, &buffer)) != GST_FLOW_OK)
+ goto beach;
+
+ data = GST_BUFFER_DATA (buffer);
+
+ if (!mxf_is_mxf_packet ((const MXFUL *) data)) {
+ GST_ERROR_OBJECT (demux, "Not an MXF packet, skipping. Key: %s",
+ mxf_ul_to_string ((const MXFUL *) data, key_str));
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+
+ memcpy (key, GST_BUFFER_DATA (buffer), 16);
+
+ /* Decode BER encoded packet length */
+ if ((data[16] & 0x80) == 0) {
+ length = data[16];
+ data_offset = 17;
+ } else {
+ guint slen = data[16] & 0x7f;
+
+ data_offset = 16 + 1 + slen;
+
+ gst_buffer_unref (buffer);
+
+ /* Must be at most 8 according to SMPTE-379M 5.3.4 */
+ if (slen > 8) {
+ GST_ERROR_OBJECT (demux, "Invalid KLV packet length: %" G_GUINT64_FORMAT,
+ slen);
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+
+ /* Now pull the length of the packet */
+ if ((ret = gst_mxf_demux_pull_range (demux, offset + 17, slen,
+ &buffer)) != GST_FLOW_OK)
+ goto beach;
+ data = GST_BUFFER_DATA (buffer);
+
+ length = 0;
+ while (slen) {
+ length = (length << 8) | *data;
+ data++;
+ slen--;
+ }
+ }
+
+ gst_buffer_unref (buffer);
+
+ /* Pull the complete KLV packet */
+ if ((ret = gst_mxf_demux_pull_range (demux, offset + data_offset, length,
+ &buffer)) != GST_FLOW_OK)
+ goto beach;
+
+ *outbuf = buffer;
+ buffer = NULL;
+ if (read)
+ *read = data_offset + length;
+
+beach:
+ if (buffer)
+ gst_buffer_unref (buffer);
+
+ return ret;
+}
+
+static void
+gst_mxf_demux_parse_footer_metadata (GstMXFDemux * demux)
+{
+ MXFPartitionPack partition;
+ MXFPrimerPack primer;
+ guint64 offset, old_offset = demux->offset;
+ MXFUL key;
+ GstBuffer *buffer = NULL;
+ guint64 read = 0;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ memcpy (&partition, &demux->partition, sizeof (MXFPartitionPack));
+ memcpy (&primer, &demux->primer, sizeof (MXFPrimerPack));
+ memset (&demux->partition, 0, sizeof (MXFPartitionPack));
+ memset (&demux->primer, 0, sizeof (MXFPrimerPack));
+
+ gst_mxf_demux_reset_metadata (demux);
+ offset =
+ demux->header_partition_pack_offset + demux->footer_partition_pack_offset;
+
+next_try:
+ mxf_partition_pack_reset (&demux->partition);
+ mxf_primer_pack_reset (&demux->primer);
+
+ ret = gst_mxf_demux_pull_klv_packet (demux, offset, &key, &buffer, &read);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto out;
+
+ if (!mxf_is_partition_pack (&key))
+ goto out;
+
+ if (!mxf_partition_pack_parse (&key, &demux->partition,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer)))
+ goto out;
+
+ offset += read;
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+
+ if (demux->partition.header_byte_count == 0) {
+ if (demux->partition.prev_partition == 0
+ || demux->partition.this_partition == 0)
+ goto out;
+
+ offset =
+ demux->header_partition_pack_offset + demux->partition.prev_partition;
+ goto next_try;
+ }
+
+ while (TRUE) {
+ ret = gst_mxf_demux_pull_klv_packet (demux, offset, &key, &buffer, &read);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ offset =
+ demux->header_partition_pack_offset + demux->partition.prev_partition;
+ goto next_try;
+ }
+
+ if (mxf_is_fill (&key)) {
+ offset += read;
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ } else if (mxf_is_primer_pack (&key)) {
+ if (!mxf_primer_pack_parse (&key, &demux->primer,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
+ offset += read;
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ offset =
+ demux->header_partition_pack_offset +
+ demux->partition.prev_partition;
+ goto next_try;
+ }
+ offset += read;
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ break;
+ } else {
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ offset =
+ demux->header_partition_pack_offset + demux->partition.prev_partition;
+ goto next_try;
+ }
+ }
+
+ /* parse metadata */
+ while (TRUE) {
+ ret = gst_mxf_demux_pull_klv_packet (demux, offset, &key, &buffer, &read);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ offset =
+ demux->header_partition_pack_offset + demux->partition.prev_partition;
+ goto next_try;
+ }
+
+ if (mxf_is_metadata (&key)) {
+ ret = gst_mxf_demux_handle_metadata (demux, &key, buffer);
+ offset += read;
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ gst_mxf_demux_reset_metadata (demux);
+ offset =
+ demux->header_partition_pack_offset +
+ demux->partition.prev_partition;
+ goto next_try;
+ }
+ } else if (mxf_is_fill (&key)) {
+ offset += read;
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ } else {
+ break;
+ }
+ }
+
+ /* resolve references etc */
+
+ if (gst_mxf_demux_handle_header_metadata_resolve_references (demux) !=
+ GST_FLOW_OK
+ || gst_mxf_demux_handle_header_metadata_update_streams (demux) !=
+ GST_FLOW_OK) {
+ offset =
+ demux->header_partition_pack_offset + demux->partition.prev_partition;
+ goto next_try;
+ }
+
+ demux->final_metadata = TRUE;
+
+out:
+ if (buffer)
+ gst_buffer_unref (buffer);
+
+ mxf_partition_pack_reset (&demux->partition);
+ mxf_primer_pack_reset (&demux->primer);
+ memcpy (&demux->partition, &partition, sizeof (MXFPartitionPack));
+ memcpy (&demux->primer, &primer, sizeof (MXFPrimerPack));
+
+ demux->offset = old_offset;
+}
+
+static GstFlowReturn
+gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, const MXFUL * key,
+ GstBuffer * buffer)
+{
+ gchar key_str[48];
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ /* In pull mode try to get the last metadata */
+ if (!demux->final_metadata && demux->random_access && demux->partition.valid
+ && demux->partition.type == MXF_PARTITION_PACK_HEADER
+ && (!demux->partition.closed || !demux->partition.complete)
+ && demux->footer_partition_pack_offset != 0) {
+ GST_DEBUG_OBJECT (demux,
+ "Open or incomplete header partition, trying to get final metadata from the last partitions");
+ gst_mxf_demux_parse_footer_metadata (demux);
+ }
+
+ /* TODO: - Pull random index pack from footer partition?
+ * - Pull all partitions for parsing all index segments and having a complete index
+ * as first thing. This also will make it possible to use the latest header
+ * metadata if it's not in the footer partition
+ */
+
+ if (demux->update_metadata
+ && !mxf_timestamp_is_unknown (&demux->preface.last_modified_date)
+ && !mxf_is_metadata (key)
+ && !mxf_is_fill (key)) {
+ if ((ret =
+ gst_mxf_demux_handle_header_metadata_resolve_references (demux)) !=
+ GST_FLOW_OK)
+ goto beach;
+ if ((ret =
+ gst_mxf_demux_handle_header_metadata_update_streams (demux)) !=
+ GST_FLOW_OK)
+ goto beach;
+ }
+
+ if (mxf_is_partition_pack (key)) {
+ ret = gst_mxf_demux_handle_partition_pack (demux, key, buffer);
+ } else if (mxf_is_primer_pack (key)) {
+ ret = gst_mxf_demux_handle_primer_pack (demux, key, buffer);
+ } else if (mxf_is_metadata (key)) {
+ ret = gst_mxf_demux_handle_metadata (demux, key, buffer);
+ } else if (mxf_is_generic_container_system_item (key)) {
+ ret =
+ gst_mxf_demux_handle_generic_container_system_item (demux, key, buffer);
+ } else if (mxf_is_generic_container_essence_element (key)) {
+ ret =
+ gst_mxf_demux_handle_generic_container_essence_element (demux, key,
+ buffer);
+ } else if (mxf_is_random_index_pack (key)) {
+ ret = gst_mxf_demux_handle_random_index_pack (demux, key, buffer);
+ } else if (mxf_is_index_table_segment (key)) {
+ ret = gst_mxf_demux_handle_index_table_segment (demux, key, buffer);
+ } else if (mxf_is_fill (key)) {
+ GST_DEBUG_OBJECT (demux,
+ "Skipping filler packet of size %" G_GUINT64_FORMAT " at offset %"
+ G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), demux->offset);
+ } else {
+ GST_DEBUG_OBJECT (demux,
+ "Skipping unknown packet of size %" G_GUINT64_FORMAT " at offset %"
+ G_GUINT64_FORMAT ", key: %s", GST_BUFFER_SIZE (buffer), demux->offset,
+ mxf_ul_to_string (key, key_str));
+ }
+
+beach:
+ return ret;
+}
+
+static GstFlowReturn
+gst_mxf_demux_pull_and_handle_klv_packet (GstMXFDemux * demux)
+{
+ GstBuffer *buffer = NULL;
+ MXFUL key;
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint64 read = 0;
+
+ ret =
+ gst_mxf_demux_pull_klv_packet (demux, demux->offset, &key, &buffer,
+ &read);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto beach;
+
+ ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer);
+
+ demux->offset += read;
+
+beach:
+ if (buffer)
+ gst_buffer_unref (buffer);
+
+ return ret;
+}
+
+static void
+gst_mxf_demux_loop (GstPad * pad)
+{
+ GstMXFDemux *demux = NULL;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
+
+ if (demux->run_in == -1) {
+ /* Skip run-in, which is at most 64K and is finished
+ * by a header partition pack */
+ while (demux->offset < 64 * 1024) {
+ GstBuffer *buffer;
+
+ if ((ret =
+ gst_mxf_demux_pull_range (demux, demux->offset, 16,
+ &buffer)) != GST_FLOW_OK)
+ break;
+
+ if (mxf_is_header_partition_pack ((const MXFUL *)
+ GST_BUFFER_DATA (buffer))) {
+ GST_DEBUG_OBJECT (demux,
+ "Found header partition pack at offset %" G_GUINT64_FORMAT,
+ demux->offset);
+ demux->run_in = demux->offset;
+ demux->header_partition_pack_offset = demux->offset;
+ gst_buffer_unref (buffer);
+ break;
+ }
+
+ demux->offset++;
+ gst_buffer_unref (buffer);
+ }
+ }
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto pause;
+
+ if (G_UNLIKELY (demux->run_in == -1)) {
+ GST_ERROR_OBJECT (demux, "No valid header partition pack found");
+ ret = GST_FLOW_ERROR;
+ goto pause;
+ }
+
+ /* Now actually do something */
+ ret = gst_mxf_demux_pull_and_handle_klv_packet (demux);
+
+ /* pause if something went wrong */
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto pause;
+
+ /* check EOS condition */
+ if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) &&
+ (demux->segment.stop != -1) &&
+ (demux->segment.last_stop >= demux->segment.stop)) {
+ ret = GST_FLOW_UNEXPECTED;
+ goto pause;
+ }
+
+ gst_object_unref (demux);
+
+ return;
+
+pause:
+ {
+ const gchar *reason = gst_flow_get_name (ret);
+
+ GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
+ gst_pad_pause_task (pad);
+
+ if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
+ if (ret == GST_FLOW_UNEXPECTED) {
+ /* perform EOS logic */
+ if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gint64 stop;
+
+ /* for segment playback we need to post when (in stream time)
+ * we stopped, this is either stop (when set) or the duration. */
+ if ((stop = demux->segment.stop) == -1)
+ stop = demux->segment.duration;
+
+ GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_segment_done (GST_OBJECT_CAST (demux),
+ GST_FORMAT_TIME, stop));
+ } else {
+ /* normal playback, send EOS to all linked pads */
+ GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
+ if (!gst_mxf_demux_push_src_event (demux, gst_event_new_eos ())) {
+ GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
+ }
+ }
+ } else {
+ GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+ ("Internal data stream error."),
+ ("stream stopped, reason %s", reason));
+ gst_mxf_demux_push_src_event (demux, gst_event_new_eos ());
+ }
+ }
+ gst_object_unref (demux);
+ return;
+ }
+}
+
+static GstFlowReturn
+gst_mxf_demux_chain (GstPad * pad, GstBuffer * inbuf)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstMXFDemux *demux = NULL;
+ MXFUL key;
+ const guint8 *data = NULL;
+ guint64 length = 0;
+ guint64 offset = 0;
+ GstBuffer *buffer = NULL;
+ gchar key_str[48];
+
+ demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
+
+ GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
+ G_GUINT64_FORMAT, GST_BUFFER_SIZE (inbuf), GST_BUFFER_OFFSET (inbuf));
+
+ if (G_UNLIKELY (GST_BUFFER_OFFSET (inbuf) == 0)) {
+ GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
+ demux->run_in = -1;
+ demux->offset = 0;
+ }
+
+ if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (inbuf) != 0)) {
+ GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
+ demux->offset = GST_BUFFER_OFFSET (inbuf);
+ }
+
+ gst_adapter_push (demux->adapter, inbuf);
+ inbuf = NULL;
+
+ while (ret == GST_FLOW_OK) {
+ if (G_UNLIKELY (demux->flushing)) {
+ GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
+ ret = GST_FLOW_WRONG_STATE;
+ break;
+ }
+
+ if (gst_adapter_available (demux->adapter) < 16)
+ break;
+
+ if (demux->run_in == -1) {
+ /* Skip run-in, which is at most 64K and is finished
+ * by a header partition pack */
+
+ while (demux->offset < 64 * 1024
+ && gst_adapter_available (demux->adapter) >= 16) {
+ data = gst_adapter_peek (demux->adapter, 16);
+
+ if (mxf_is_header_partition_pack ((const MXFUL *)
+ data)) {
+ GST_DEBUG_OBJECT (demux,
+ "Found header partition pack at offset %" G_GUINT64_FORMAT,
+ demux->offset);
+ demux->run_in = demux->offset;
+ demux->header_partition_pack_offset = demux->offset;
+ break;
+ }
+ gst_adapter_flush (demux->adapter, 1);
+ }
+ }
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ break;
+
+ /* Need more data */
+ if (demux->run_in == -1 && demux->offset < 64 * 1024)
+ break;
+
+ if (G_UNLIKELY (demux->run_in == -1)) {
+ GST_ERROR_OBJECT (demux, "No valid header partition pack found");
+ ret = GST_FLOW_ERROR;
+ break;
+ }
+
+ if (gst_adapter_available (demux->adapter) < 17)
+ break;
+
+ /* Now actually do something */
+ memset (&key, 0, sizeof (MXFUL));
+
+ /* Pull 16 byte key and first byte of BER encoded length */
+ data = gst_adapter_peek (demux->adapter, 17);
+
+ if (!mxf_is_mxf_packet ((const MXFUL *) data)) {
+ GST_ERROR_OBJECT (demux, "Not an MXF packet, skipping. Key: %s",
+ mxf_ul_to_string ((const MXFUL *) data, key_str));
+ ret = GST_FLOW_ERROR;
+ break;
+ }
+
+ memcpy (&key, data, 16);
+
+ /* Decode BER encoded packet length */
+ if ((data[16] & 0x80) == 0) {
+ length = data[16];
+ offset = 17;
+ } else {
+ guint slen = data[16] & 0x7f;
+
+ offset = 16 + 1 + slen;
+
+ /* Must be at most 8 according to SMPTE-379M 5.3.4 */
+ if (slen > 8) {
+ GST_ERROR_OBJECT (demux,
+ "Invalid KLV packet length: %" G_GUINT64_FORMAT, slen);
+ ret = GST_FLOW_ERROR;
+ break;
+ }
+
+ if (gst_adapter_available (demux->adapter) < 17 + slen)
+ break;
+
+ data = gst_adapter_peek (demux->adapter, 17 + slen);
+ data += 17;
+
+ length = 0;
+ while (slen) {
+ length = (length << 8) | *data;
+ data++;
+ slen--;
+ }
+ }
+
+ if (gst_adapter_available (demux->adapter) < offset + length)
+ break;
+
+ gst_adapter_flush (demux->adapter, offset);
+ buffer = gst_adapter_take_buffer (demux->adapter, length);
+
+ ret = gst_mxf_demux_handle_klv_packet (demux, &key, buffer);
+ gst_buffer_unref (buffer);
+ }
+
+ gst_object_unref (demux);
+
+ return ret;
+}
+
+static gboolean
+gst_mxf_demux_src_event (GstPad * pad, GstEvent * event)
+{
+ GstMXFDemux *demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
+ gboolean ret;
+
+ GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ /* TODO: handle this */
+ gst_event_unref (event);
+ ret = FALSE;
+ break;
+ default:
+ ret = gst_pad_push_event (demux->sinkpad, event);
+ break;
+ }
+
+ gst_object_unref (demux);
+
+ return ret;
+}
+
+static const GstQueryType *
+gst_mxf_demux_src_query_type (GstPad * pad)
+{
+ static const GstQueryType types[] = {
+ GST_QUERY_POSITION,
+ GST_QUERY_DURATION,
+ 0
+ };
+
+ return types;
+}
+
+static gboolean
+gst_mxf_demux_src_query (GstPad * pad, GstQuery * query)
+{
+ GstMXFDemux *demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
+ gboolean ret = FALSE;
+ GstMXFPad *mxfpad = GST_MXF_PAD (pad);
+
+ GST_DEBUG_OBJECT (pad, "handling query %s",
+ gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_POSITION:
+ {
+ GstFormat format;
+ gint64 pos;
+
+ gst_query_parse_position (query, &format, NULL);
+ if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
+ goto error;
+
+ pos = mxfpad->essence_element_count;
+ if (format == GST_FORMAT_TIME) {
+ if (!mxfpad->material_track || mxfpad->material_track->edit_rate.n == 0
+ || mxfpad->material_track->edit_rate.d == 0)
+ goto error;
+
+ pos =
+ gst_util_uint64_scale (pos + mxfpad->material_track->origin,
+ GST_SECOND * mxfpad->material_track->edit_rate.d,
+ mxfpad->material_track->edit_rate.n);
+ }
+
+ GST_DEBUG_OBJECT (pad,
+ "Returning position %" G_GINT64_FORMAT " in format %s", pos,
+ gst_format_get_name (format));
+
+ gst_query_set_position (query, format, pos);
+ ret = TRUE;
+
+ break;
+ }
+ case GST_QUERY_DURATION:{
+ gint64 duration;
+ GstFormat format;
+
+ gst_query_parse_duration (query, &format, NULL);
+ if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
+ goto error;
+
+ if (!mxfpad->material_track || !mxfpad->material_track->sequence)
+ goto error;
+
+ duration = mxfpad->material_track->sequence->duration;
+ if (format == GST_FORMAT_TIME) {
+ if (mxfpad->material_track->edit_rate.n == 0 ||
+ mxfpad->material_track->edit_rate.d == 0)
+ goto error;
+
+ duration =
+ gst_util_uint64_scale (duration,
+ GST_SECOND * mxfpad->material_track->edit_rate.d,
+ mxfpad->material_track->edit_rate.n);
+ }
+
+ GST_DEBUG_OBJECT (pad,
+ "Returning duration %" G_GINT64_FORMAT " in format %s", duration,
+ gst_format_get_name (format));
+
+ gst_query_set_duration (query, format, duration);
+ ret = TRUE;
+ break;
+ }
+ default:
+ /* else forward upstream */
+ ret = gst_pad_peer_query (demux->sinkpad, query);
+ break;
+ }
+
+done:
+ gst_object_unref (demux);
+ return ret;
+
+ /* ERRORS */
+error:
+ {
+ GST_DEBUG_OBJECT (pad, "query failed");
+ goto done;
+ }
+}
+
+static gboolean
+gst_mxf_demux_sink_activate (GstPad * sinkpad)
+{
+ if (gst_pad_check_pull_range (sinkpad)) {
+ return gst_pad_activate_pull (sinkpad, TRUE);
+ } else {
+ return gst_pad_activate_push (sinkpad, TRUE);
+ }
+}
+
+static gboolean
+gst_mxf_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
+{
+ GstMXFDemux *demux;
+
+ demux = GST_MXF_DEMUX (gst_pad_get_parent (sinkpad));
+
+ demux->random_access = FALSE;
+
+ gst_object_unref (demux);
+
+ return TRUE;
+}
+
+static gboolean
+gst_mxf_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
+{
+ GstMXFDemux *demux;
+
+ demux = GST_MXF_DEMUX (gst_pad_get_parent (sinkpad));
+
+ if (active) {
+ demux->random_access = TRUE;
+ gst_object_unref (demux);
+ return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_mxf_demux_loop,
+ sinkpad);
+ } else {
+ demux->random_access = FALSE;
+ gst_object_unref (demux);
+ return gst_pad_stop_task (sinkpad);
+ }
+}
+
+static gboolean
+gst_mxf_demux_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstMXFDemux *demux;
+ gboolean ret = FALSE;
+
+ demux = GST_MXF_DEMUX (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (pad, "handling event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_START:
+ demux->flushing = TRUE;
+ ret = gst_mxf_demux_push_src_event (demux, event);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ gst_mxf_demux_flush (demux, TRUE);
+ ret = gst_mxf_demux_push_src_event (demux, event);
+ break;
+ case GST_EVENT_EOS:
+ if (!gst_mxf_demux_push_src_event (demux, event))
+ GST_WARNING_OBJECT (pad, "failed pushing EOS on streams");
+ ret = TRUE;
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ /* TODO: handle this */
+ gst_event_unref (event);
+ ret = FALSE;
+ break;
+ default:
+ ret = gst_mxf_demux_push_src_event (demux, event);
+ break;
+ }
+
+ gst_object_unref (demux);
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_mxf_demux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstMXFDemux *demux = GST_MXF_DEMUX (element);
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_mxf_demux_reset (demux);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void
+gst_mxf_demux_finalize (GObject * object)
+{
+ GstMXFDemux *demux = GST_MXF_DEMUX (object);
+
+ if (demux->adapter) {
+ g_object_unref (demux->adapter);
+ demux->adapter = NULL;
+ }
+
+ if (demux->new_seg_event) {
+ gst_event_unref (demux->new_seg_event);
+ demux->new_seg_event = NULL;
+ }
+
+ if (demux->close_seg_event) {
+ gst_event_unref (demux->close_seg_event);
+ demux->close_seg_event = NULL;
+ }
+
+ if (demux->src) {
+ g_ptr_array_foreach (demux->src, (GFunc) gst_mxf_demux_remove_pad, demux);
+ g_ptr_array_foreach (demux->src, (GFunc) gst_object_unref, NULL);
+ g_ptr_array_free (demux->src, TRUE);
+ demux->src = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_mxf_demux_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&mxf_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&audio_src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&video_src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&data_src_template));
+ gst_element_class_set_details_simple (element_class, "MXF Demuxer",
+ "Codec/Demuxer",
+ "Demux MXF files", "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+}
+
+static void
+gst_mxf_demux_class_init (GstMXFDemuxClass * klass)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ GST_DEBUG_CATEGORY_INIT (mxfdemux_debug, "mxfdemux", 0, "MXF demuxer");
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_mxf_demux_finalize);
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_change_state);
+}
+
+static void
+gst_mxf_demux_init (GstMXFDemux * demux, GstMXFDemuxClass * g_class)
+{
+ demux->sinkpad =
+ gst_pad_new_from_static_template (&mxf_sink_template, "sink");
+
+ gst_pad_set_event_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_event));
+ gst_pad_set_chain_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_chain));
+ gst_pad_set_activate_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate));
+ gst_pad_set_activatepull_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_pull));
+ gst_pad_set_activatepush_function (demux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_mxf_demux_sink_activate_push));
+
+ gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
+
+ demux->adapter = gst_adapter_new ();
+ demux->src = g_ptr_array_new ();
+ gst_segment_init (&demux->segment, GST_FORMAT_TIME);
+
+ gst_mxf_demux_reset (demux);
+}
diff --git a/gst/mxf/mxfdemux.h b/gst/mxf/mxfdemux.h
new file mode 100644
index 00000000..b49d919c
--- /dev/null
+++ b/gst/mxf/mxfdemux.h
@@ -0,0 +1,108 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MXF_DEMUX_H__
+#define __MXF_DEMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#include "mxfparse.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_MXF_DEMUX \
+ (gst_mxf_demux_get_type())
+#define GST_MXF_DEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MXF_DEMUX,GstMXFDemux))
+#define GST_MXF_DEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MXF_DEMUX,GstMXFDemuxClass))
+#define GST_IS_MXF_DEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MXF_DEMUX))
+#define GST_IS_MXF_DEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MXF_DEMUX))
+typedef struct _GstMXFDemux GstMXFDemux;
+typedef struct _GstMXFDemuxClass GstMXFDemuxClass;
+
+struct _GstMXFDemux
+{
+ GstElement element;
+
+ GstPad *sinkpad;
+ GPtrArray *src;
+
+ GstAdapter *adapter;
+
+ GstSegment segment;
+
+ GstEvent *new_seg_event;
+ GstEvent *close_seg_event;
+
+ guint64 offset;
+
+ gboolean random_access;
+ gboolean flushing;
+
+ guint64 run_in;
+
+ guint64 header_partition_pack_offset;
+ guint64 footer_partition_pack_offset;
+
+ /* MXF file state */
+ MXFPartitionPack partition;
+ MXFPrimerPack primer;
+
+ /* Structural metadata */
+ gboolean update_metadata;
+ gboolean final_metadata;
+ MXFMetadataPreface preface;
+ GArray *identification;
+ MXFMetadataContentStorage content_storage;
+ GArray *essence_container_data;
+ GArray *material_package;
+ GArray *source_package;
+ GPtrArray *package;
+ GArray *track;
+ GArray *sequence;
+ GArray *structural_component;
+ GArray *locator;
+
+ GPtrArray *descriptor;
+ GArray *generic_descriptor;
+ GArray *file_descriptor;
+ GArray *generic_sound_essence_descriptor;
+ GArray *generic_picture_essence_descriptor;
+ GArray *cdci_picture_essence_descriptor;
+ GArray *mpeg_video_descriptor;
+ GArray *wave_audio_essence_descriptor;
+ GArray *multiple_descriptor;
+
+ MXFUMID current_package_uid;
+ MXFMetadataGenericPackage *current_package;
+};
+
+struct _GstMXFDemuxClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_mxf_demux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __MXF_DEMUX_H__ */
diff --git a/gst/mxf/mxfmpeg.c b/gst/mxf/mxfmpeg.c
new file mode 100644
index 00000000..e46d5388
--- /dev/null
+++ b/gst/mxf/mxfmpeg.c
@@ -0,0 +1,318 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Implementation of SMPTE 381M - Mapping MPEG streams into the MXF
+ * Generic Container
+ */
+
+/* TODO:
+ * - Handle PES streams
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+
+#include "mxfmpeg.h"
+
+GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
+#define GST_CAT_DEFAULT mxf_debug
+
+/* SMPTE 381M 8.1 - ULs of local tags */
+static const guint8 _single_sequence_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x02, 0x00, 0x00
+};
+
+static const guint8 _constant_b_frames_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x03, 0x00, 0x00
+};
+
+static const guint8 _coded_content_type_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x04, 0x00, 0x00
+};
+
+static const guint8 _low_delay_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x05, 0x00, 0x00
+};
+
+static const guint8 _closed_gop_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x06, 0x00, 0x00
+};
+
+static const guint8 _identical_gop_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x07, 0x00, 0x00
+};
+
+static const guint8 _max_gop_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x08, 0x00, 0x00
+};
+
+static const guint8 _b_picture_count_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x09, 0x00, 0x00
+};
+
+static const guint8 _bitrate_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x0b, 0x00, 0x00
+};
+
+static const guint8 _profile_and_level_ul[] = {
+ 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x05, 0x04, 0x01, 0x06, 0x02, 0x01,
+ 0x0a, 0x00, 0x00
+};
+
+gboolean
+mxf_metadata_mpeg_video_descriptor_parse (const MXFUL * key,
+ MXFMetadataMPEGVideoDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataMPEGVideoDescriptor));
+
+ if (!mxf_metadata_cdci_picture_essence_descriptor_parse (key,
+ (MXFMetadataCDCIPictureEssenceDescriptor *) descriptor, primer, type,
+ data, size))
+ goto error;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ MXFUL *tag_ul = NULL;
+
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ if (!(tag_ul =
+ (MXFUL *) g_hash_table_lookup (primer->mappings,
+ GUINT_TO_POINTER (((guint) tag)))))
+ goto next;
+
+ if (memcmp (tag_ul, &_single_sequence_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->single_sequence = GST_READ_UINT8 (tag_data);
+ } else if (memcmp (tag_ul, &_constant_b_frames_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->const_b_frames = GST_READ_UINT8 (tag_data);
+ } else if (memcmp (tag_ul, &_coded_content_type_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->coded_content_type = GST_READ_UINT8 (tag_data);
+ } else if (memcmp (tag_ul, &_low_delay_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->low_delay = GST_READ_UINT8 (tag_data);
+ } else if (memcmp (tag_ul, &_closed_gop_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->closed_gop = GST_READ_UINT8 (tag_data);
+ } else if (memcmp (tag_ul, &_identical_gop_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->identical_gop = GST_READ_UINT8 (tag_data);
+ } else if (memcmp (tag_ul, &_max_gop_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 2)
+ goto error;
+ descriptor->max_gop = GST_READ_UINT16_BE (tag_data);
+ } else if (memcmp (tag_ul, &_b_picture_count_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 2)
+ goto error;
+ descriptor->b_picture_count = GST_READ_UINT16_BE (tag_data);
+ } else if (memcmp (tag_ul, &_bitrate_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->bitrate = GST_READ_UINT32_BE (tag_data);
+ } else if (memcmp (tag_ul, &_profile_and_level_ul, 16) == 0) {
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->profile_and_level = GST_READ_UINT8 (tag_data);
+ } else {
+ if (type != MXF_METADATA_MPEG_VIDEO_DESCRIPTOR)
+ goto next;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
+ goto error;
+ }
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed mpeg video descriptors:");
+ GST_DEBUG (" single sequence = %s",
+ (descriptor->single_sequence) ? "yes" : "no");
+ GST_DEBUG (" constant b frames = %s",
+ (descriptor->single_sequence) ? "yes" : "no");
+ GST_DEBUG (" coded content type = %u", descriptor->coded_content_type);
+ GST_DEBUG (" low delay = %s", (descriptor->low_delay) ? "yes" : "no");
+ GST_DEBUG (" closed gop = %s", (descriptor->closed_gop) ? "yes" : "no");
+ GST_DEBUG (" identical gop = %s",
+ (descriptor->identical_gop) ? "yes" : "no");
+ GST_DEBUG (" max gop = %u", descriptor->max_gop);
+ GST_DEBUG (" b picture count = %u", descriptor->b_picture_count);
+ GST_DEBUG (" bitrate = %u", descriptor->bitrate);
+ GST_DEBUG (" profile & level = %u", descriptor->profile_and_level);
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid mpeg video descriptor");
+ mxf_metadata_mpeg_video_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void mxf_metadata_mpeg_video_descriptor_reset
+ (MXFMetadataMPEGVideoDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ mxf_metadata_cdci_picture_essence_descriptor_reset (
+ (MXFMetadataCDCIPictureEssenceDescriptor *) descriptor);
+
+ memset (descriptor, 0, sizeof (MXFMetadataMPEGVideoDescriptor));
+}
+
+gboolean
+mxf_is_mpeg_video_essence_track (const MXFMetadataTrack * track)
+{
+ guint i;
+
+ g_return_val_if_fail (track != NULL, FALSE);
+
+ if (track->descriptor == NULL)
+ return FALSE;
+
+ for (i = 0; i < track->n_descriptor; i++) {
+ MXFMetadataFileDescriptor *d = track->descriptor[i];
+ MXFUL *key = &d->essence_container;
+ /* SMPTE 381M 7 */
+ if (mxf_is_generic_container_essence_container_label (key) &&
+ key->u[12] == 0x02 &&
+ (key->u[13] == 0x04 ||
+ key->u[13] == 0x07 || key->u[13] == 0x08 || key->u[13] == 0x09))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GstFlowReturn
+mxf_mpeg_video_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
+ GstCaps * caps, MXFMetadataGenericPackage * package,
+ MXFMetadataTrack * track, MXFMetadataStructuralComponent * component,
+ gpointer mapping_data, GstBuffer ** outbuf)
+{
+ *outbuf = buffer;
+
+ /* SMPTE 381M 6.1 */
+ if (key->u[12] != 0x15 || (key->u[14] != 0x05 && key->u[14] != 0x06
+ && key->u[14] != 0x07)) {
+ GST_ERROR ("Invalid MPEG video essence element");
+ return GST_FLOW_ERROR;
+ }
+
+ return GST_FLOW_OK;
+}
+
+
+GstCaps *
+mxf_mpeg_video_create_caps (MXFMetadataGenericPackage * package,
+ MXFMetadataTrack * track, GstTagList ** tags,
+ MXFEssenceElementHandler * handler, gpointer * mapping_data)
+{
+ MXFMetadataMPEGVideoDescriptor *d = NULL;
+ MXFMetadataFileDescriptor *f = NULL;
+ guint i;
+
+ g_return_val_if_fail (package != NULL, NULL);
+ g_return_val_if_fail (track != NULL, NULL);
+
+ if (track->descriptor == NULL) {
+ GST_ERROR ("No descriptor found for this track");
+ return NULL;
+ }
+
+ for (i = 0; i < track->n_descriptor; i++) {
+ if (((MXFMetadataGenericDescriptor *) track->descriptor[i])->type ==
+ MXF_METADATA_MPEG_VIDEO_DESCRIPTOR) {
+ d = (MXFMetadataMPEGVideoDescriptor *) track->descriptor[i];
+ f = track->descriptor[i];
+ break;
+ } else if (((MXFMetadataGenericDescriptor *) track->descriptor[i])->type ==
+ MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR
+ || ((MXFMetadataGenericDescriptor *) track->descriptor[i])->type ==
+ MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR
+ || ((MXFMetadataGenericDescriptor *) track->descriptor[i])->type ==
+ MXF_METADATA_FILE_DESCRIPTOR) {
+ f = track->descriptor[i];
+ }
+ }
+
+ if (!f) {
+ GST_ERROR ("No descriptor found for this track");
+ return NULL;
+ }
+
+ *handler = mxf_mpeg_video_handle_essence_element;
+ /* SMPTE 381M 7 */
+ if (f->essence_container.u[13] == 0x04) {
+ /* FIXME: get mpeg version somehow */
+ GST_DEBUG ("Found MPEG ES stream");
+ return gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
+ "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ } else if (f->essence_container.u[13] == 0x07) {
+ GST_ERROR ("MPEG PES streams not supported yet");
+ return NULL;
+ } else if (f->essence_container.u[13] == 0x08) {
+ /* FIXME: get mpeg version somehow */
+ GST_DEBUG ("Found MPEG PS stream");
+ return gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
+ "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+ } else if (f->essence_container.u[13] == 0x09) {
+ GST_DEBUG ("Found MPEG TS stream");
+ return gst_caps_new_simple ("video/mpegts", NULL);
+ }
+ return NULL;
+}
diff --git a/gst/mxf/mxfmpeg.h b/gst/mxf/mxfmpeg.h
new file mode 100644
index 00000000..e251cb06
--- /dev/null
+++ b/gst/mxf/mxfmpeg.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Implementation of SMPTE 381M - Mapping MPEG streams into the MXF
+ * Generic Container
+ */
+
+#ifndef __MXF_MPEG_H__
+#define __MXF_MPEG_H__
+
+#include <gst/gst.h>
+
+#include "mxfparse.h"
+
+/* SMPTE 381M 8.1.1 */
+#define MXF_METADATA_MPEG_VIDEO_DESCRIPTOR 0x0151
+
+/* SMPTE 381M 8.1 */
+typedef struct {
+ MXFMetadataCDCIPictureEssenceDescriptor parent;
+
+ gboolean single_sequence;
+ gboolean const_b_frames;
+ guint8 coded_content_type;
+ gboolean low_delay;
+
+ gboolean closed_gop;
+ gboolean identical_gop;
+ guint16 max_gop;
+
+ guint16 b_picture_count;
+ guint32 bitrate;
+ guint8 profile_and_level;
+} MXFMetadataMPEGVideoDescriptor;
+
+gboolean mxf_metadata_mpeg_video_descriptor_parse (const MXFUL *key, MXFMetadataMPEGVideoDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_mpeg_video_descriptor_reset (MXFMetadataMPEGVideoDescriptor *descriptor);
+
+gboolean mxf_is_mpeg_video_essence_track (const MXFMetadataTrack *track);
+
+GstCaps *
+mxf_mpeg_video_create_caps (MXFMetadataGenericPackage *package, MXFMetadataTrack *track, GstTagList **tags, MXFEssenceElementHandler *handler, gpointer *mapping_data);
+
+#endif /* __MXF_MPEG_H__ */
diff --git a/gst/mxf/mxfparse.c b/gst/mxf/mxfparse.c
new file mode 100644
index 00000000..49f5d685
--- /dev/null
+++ b/gst/mxf/mxfparse.c
@@ -0,0 +1,2692 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <string.h>
+
+#include "mxfparse.h"
+
+GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
+#define GST_CAT_DEFAULT mxf_debug
+
+/* SMPTE 377M 3.3: A value of 0 for every field means unknown timestamp */
+static const MXFTimestamp mxf_timestamp_unknown = { 0, 0, 0, 0, 0, 0, 0 };
+
+/* FIXME: are zero UMID/UL invalid? Should be in SMPTE 298M, 330M or 336M */
+static const MXFUMID umid_zero = { {0,} };
+static const MXFUL key_zero = { {0,} };
+
+/* UL common to all MXF UL */
+static const guint8 mxf_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
+
+/* SMPTE 377M 6.1 */
+static const guint8 partition_pack_key[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
+ 0x01
+};
+
+/* SMPTE 336M */
+static const guint8 fill_key[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x02, 0x10,
+ 0x01, 0x00, 0x00, 0x00
+};
+
+/* SMPTE 377M 8.1 */
+static const guint8 primer_pack_key[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
+ 0x01, 0x05, 0x01, 0x00
+};
+
+/* SMPTE 377M 8.6 */
+static const guint8 metadata_key[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01,
+ 0x01
+};
+
+static const guint8 random_index_pack_key[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
+ 0x01, 0x11, 0x01, 0x00
+};
+
+static const guint8 index_table_segment_key[] =
+ { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01,
+ 0x01, 0x10, 0x01, 0x00
+};
+
+gboolean
+mxf_is_mxf_packet (const MXFUL * key)
+{
+ return (memcmp (key, mxf_key, 4) == 0);
+}
+
+/* SMPTE 377M 6.1: Check if this is a valid partition pack */
+gboolean
+mxf_is_partition_pack (const MXFUL * key)
+{
+ if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] >= 0x02
+ && key->u[13] <= 0x04 && key->u[14] < 0x05 && key->u[15] == 0x00)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* SMPTE 377M 6.2: header partition pack has byte 14 == 0x02 */
+gboolean
+mxf_is_header_partition_pack (const MXFUL * key)
+{
+ if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x02 &&
+ key->u[14] < 0x05 && key->u[15] == 0x00)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* SMPTE 377M 6.3: body partition pack has byte 14 == 0x03 */
+gboolean
+mxf_is_body_partition_pack (const MXFUL * key)
+{
+ if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x03 &&
+ key->u[14] < 0x05 && key->u[15] == 0x00)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* SMPTE 377M 6.4: footer partition pack has byte 14 == 0x04 */
+gboolean
+mxf_is_footer_partition_pack (const MXFUL * key)
+{
+ if (memcmp (key, partition_pack_key, 13) == 0 && key->u[13] == 0x04 &&
+ key->u[14] < 0x05 && key->u[15] == 0x00)
+ return TRUE;
+
+ return FALSE;
+}
+
+gboolean
+mxf_is_fill (const MXFUL * key)
+{
+ return (memcmp (key, fill_key, 16) == 0);
+}
+
+gboolean
+mxf_is_primer_pack (const MXFUL * key)
+{
+ return (memcmp (key, primer_pack_key, 16) == 0);
+}
+
+gboolean
+mxf_is_metadata (const MXFUL * key)
+{
+ return (memcmp (key, metadata_key, 13) == 0 && key->u[15] == 0x00);
+}
+
+gboolean
+mxf_is_random_index_pack (const MXFUL * key)
+{
+ return (memcmp (key, random_index_pack_key, 16) == 0);
+}
+
+gboolean
+mxf_is_index_table_segment (const MXFUL * key)
+{
+ return (memcmp (key, index_table_segment_key, 16) == 0);
+}
+
+/* SMPTE 379M 6.2.1 */
+gboolean
+mxf_is_generic_container_system_item (const MXFUL * key)
+{
+ return (memcmp (key, mxf_key, 4) == 0 && key->u[4] == 0x02
+ && key->u[6] == 0x01 && key->u[8] == 0x0d && key->u[9] == 0x01
+ && key->u[10] == 0x03 && key->u[11] == 0x01 && (key->u[12] == 0x04
+ || key->u[12] == 0x14));
+}
+
+/* SMPTE 379M 7.1 */
+gboolean
+mxf_is_generic_container_essence_element (const MXFUL * key)
+{
+ return (memcmp (key, mxf_key, 4) == 0 && key->u[4] == 0x01
+ && key->u[5] == 0x02 && key->u[6] == 0x01 && key->u[8] == 0x0d
+ && key->u[9] == 0x01 && key->u[10] == 0x03 && key->u[11] == 0x01
+ && (key->u[12] == 0x05 || key->u[12] == 0x06 || key->u[12] == 0x07
+ || key->u[12] == 0x15 || key->u[12] == 0x16 || key->u[12] == 0x17
+ || key->u[12] == 0x18));
+}
+
+/* SMPTE 379M 8 */
+gboolean
+mxf_is_generic_container_essence_container_label (const MXFUL * key)
+{
+ return (key->u[0] == 0x06 &&
+ key->u[1] == 0x0e &&
+ key->u[2] == 0x2b &&
+ key->u[3] == 0x34 &&
+ key->u[4] == 0x04 &&
+ key->u[5] == 0x01 &&
+ key->u[6] == 0x01 &&
+ key->u[8] == 0x0d &&
+ key->u[9] == 0x01 &&
+ key->u[10] == 0x03 &&
+ key->u[11] == 0x01 && (key->u[12] == 0x01 || key->u[12] == 0x02));
+}
+
+gboolean
+mxf_ul_is_equal (const MXFUL * a, const MXFUL * b)
+{
+ return (memcmp (a, b, 16) == 0);
+}
+
+gboolean
+mxf_ul_is_zero (const MXFUL * key)
+{
+ return (memcmp (key, &key_zero, 16) == 0);
+}
+
+gchar *
+mxf_ul_to_string (const MXFUL * key, gchar str[48])
+{
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (str != NULL, NULL);
+
+ g_snprintf (str, 48,
+ "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
+ key->u[0], key->u[1], key->u[2], key->u[3], key->u[4], key->u[5],
+ key->u[6], key->u[7], key->u[8], key->u[9], key->u[10], key->u[11],
+ key->u[12], key->u[13], key->u[14], key->u[15]);
+
+ return str;
+}
+
+gboolean
+mxf_umid_is_equal (const MXFUMID * a, const MXFUMID * b)
+{
+ return (memcmp (a, b, 32) == 0);
+}
+
+gboolean
+mxf_umid_is_zero (const MXFUMID * umid)
+{
+ return (memcmp (umid, &umid_zero, 32) == 0);
+}
+
+gchar *
+mxf_umid_to_string (const MXFUMID * key, gchar str[96])
+{
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (str != NULL, NULL);
+
+ g_snprintf (str, 96,
+ "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x."
+ "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
+ key->u[0], key->u[1], key->u[2], key->u[3], key->u[4], key->u[5],
+ key->u[6], key->u[7], key->u[8], key->u[9], key->u[10], key->u[11],
+ key->u[12], key->u[13], key->u[14], key->u[15],
+ key->u[16],
+ key->u[17],
+ key->u[18],
+ key->u[19],
+ key->u[20],
+ key->u[21],
+ key->u[22],
+ key->u[23],
+ key->u[24],
+ key->u[25],
+ key->u[26], key->u[27], key->u[28], key->u[29], key->u[30], key->u[31]
+ );
+
+ return str;
+}
+
+
+static guint
+gst_mxf_ul_hash (const MXFUL * key)
+{
+ guint32 ret = 0;
+ gint i;
+
+ for (i = 0; i < 4; i++)
+ ret ^=
+ (key->u[i * 4 + 0] << 24) | (key->u[i * 4 + 1] << 16) | (key->u[i * 4 +
+ 2] << 8) | (key->u[i * 4 + 3] << 0);
+
+ return ret;
+}
+
+static gboolean
+gst_mxf_ul_equal (const MXFUL * a, const MXFUL * b)
+{
+ return (memcmp (a, b, 16) == 0);
+}
+
+gboolean
+mxf_timestamp_parse (MXFTimestamp * timestamp, const guint8 * data, gsize size)
+{
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (timestamp != NULL, FALSE);
+
+ memset (timestamp, 0, sizeof (MXFTimestamp));
+
+ if (size < 8)
+ return FALSE;
+
+ timestamp->year = GST_READ_UINT16_BE (data);
+ timestamp->month = GST_READ_UINT8 (data + 2);
+ timestamp->day = GST_READ_UINT8 (data + 3);
+ timestamp->hour = GST_READ_UINT8 (data + 4);
+ timestamp->minute = GST_READ_UINT8 (data + 5);
+ timestamp->second = GST_READ_UINT8 (data + 6);
+ timestamp->quarter_msecond = GST_READ_UINT8 (data + 7);
+
+ return TRUE;
+}
+
+gboolean
+mxf_timestamp_is_unknown (const MXFTimestamp * a)
+{
+ return (memcmp (a, &mxf_timestamp_unknown, sizeof (MXFTimestamp)) == 0);
+}
+
+gint
+mxf_timestamp_compare (const MXFTimestamp * a, const MXFTimestamp * b)
+{
+ gint diff;
+
+ if ((diff = a->year - b->year) != 0)
+ return diff;
+ else if ((diff = a->month - b->month) != 0)
+ return diff;
+ else if ((diff = a->day - b->day) != 0)
+ return diff;
+ else if ((diff = a->hour - b->hour) != 0)
+ return diff;
+ else if ((diff = a->minute - b->minute) != 0)
+ return diff;
+ else if ((diff = a->second - b->second) != 0)
+ return diff;
+ else if ((diff = a->quarter_msecond - b->quarter_msecond) != 0)
+ return diff;
+ else
+ return 0;
+}
+
+gboolean
+mxf_fraction_parse (MXFFraction * fraction, const guint8 * data, guint16 size)
+{
+ g_return_val_if_fail (fraction != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (fraction, 0, sizeof (MXFFraction));
+
+ if (size < 8)
+ return FALSE;
+
+ fraction->n = GST_READ_UINT32_BE (data);
+ fraction->d = GST_READ_UINT32_BE (data + 4);
+
+ return TRUE;
+}
+
+gchar *
+mxf_utf16_to_utf8 (const guint8 * data, guint16 size)
+{
+ gchar *ret;
+ GError *error = NULL;
+
+ ret =
+ g_convert ((const gchar *) data, size, "UTF-8", "UTF-16BE", NULL, NULL,
+ &error);
+
+ if (ret == NULL) {
+ GST_WARNING ("UTF-16-BE to UTF-8 conversion failed: %s", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ return ret;
+}
+
+gboolean
+mxf_product_version_parse (MXFProductVersion * product_version,
+ const guint8 * data, gsize size)
+{
+ g_return_val_if_fail (product_version != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (product_version, 0, sizeof (MXFProductVersion));
+
+ if (size < 10)
+ return FALSE;
+
+ product_version->major = GST_READ_UINT16_BE (data);
+ product_version->minor = GST_READ_UINT16_BE (data + 2);
+ product_version->patch = GST_READ_UINT16_BE (data + 4);
+ product_version->build = GST_READ_UINT16_BE (data + 6);
+ product_version->release = GST_READ_UINT16_BE (data + 8);
+
+ return TRUE;
+}
+
+/* SMPTE 377M 6.1, Table 2 */
+gboolean
+mxf_partition_pack_parse (const MXFUL * key, MXFPartitionPack * pack,
+ const guint8 * data, gsize size)
+{
+ gint i;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (size >= 84, FALSE);
+
+ memset (pack, 0, sizeof (MXFPartitionPack));
+
+ if (key->u[13] == 0x02)
+ pack->type = MXF_PARTITION_PACK_HEADER;
+ else if (key->u[13] == 0x03)
+ pack->type = MXF_PARTITION_PACK_BODY;
+ else if (key->u[13] == 0x04)
+ pack->type = MXF_PARTITION_PACK_FOOTER;
+
+ pack->closed = (key->u[14] == 0x02 || key->u[14] == 0x04);
+ pack->complete = (key->u[14] == 0x03 || key->u[14] == 0x04);
+
+ pack->major_version = GST_READ_UINT16_BE (data);
+ if (pack->major_version != 1)
+ goto error;
+ data += 2;
+ size -= 2;
+
+ pack->minor_version = GST_READ_UINT16_BE (data);
+ data += 2;
+ size -= 2;
+
+ pack->kag_size = GST_READ_UINT32_BE (data);
+ data += 4;
+ size -= 4;
+
+ pack->this_partition = GST_READ_UINT64_BE (data);
+ data += 8;
+ size -= 8;
+
+ pack->prev_partition = GST_READ_UINT64_BE (data);
+ data += 8;
+ size -= 8;
+
+ pack->footer_partition = GST_READ_UINT64_BE (data);
+ data += 8;
+ size -= 8;
+
+ pack->header_byte_count = GST_READ_UINT64_BE (data);
+ data += 8;
+ size -= 8;
+
+ pack->index_byte_count = GST_READ_UINT64_BE (data);
+ data += 8;
+ size -= 8;
+
+ pack->index_sid = GST_READ_UINT32_BE (data);
+ data += 4;
+ size -= 4;
+
+ pack->body_offset = GST_READ_UINT64_BE (data);
+ data += 8;
+ size -= 8;
+
+ pack->body_sid = GST_READ_UINT32_BE (data);
+ data += 4;
+ size -= 4;
+
+ memcpy (&pack->operational_pattern, data, 16);
+ data += 16;
+ size -= 16;
+
+ pack->n_essence_containers = GST_READ_UINT32_BE (data);
+ data += 4;
+ size -= 4;
+
+ if (GST_READ_UINT32_BE (data) != 16)
+ goto error;
+ data += 4;
+ size -= 4;
+
+ if (size < 16 * pack->n_essence_containers)
+ goto error;
+
+ if (pack->n_essence_containers) {
+ pack->essence_containers = g_new (MXFUL, pack->n_essence_containers);
+ for (i = 0; i < pack->n_essence_containers; i++)
+ memcpy (&pack->essence_containers[i], data + i * 16, 16);
+ }
+
+ pack->valid = TRUE;
+ GST_DEBUG ("Parsed partition pack: \n"
+ " type = %s, closed = %s, complete = %s\n"
+ " MXF version = %u.%u\n"
+ " KAG size = %u\n"
+ " this partition offset = %" G_GUINT64_FORMAT "\n"
+ " previous partition offset = %" G_GUINT64_FORMAT "\n"
+ " footer partition offset = %" G_GUINT64_FORMAT "\n"
+ " header size = %" G_GUINT64_FORMAT "\n"
+ " index sid = %u, size %" G_GUINT64_FORMAT "\n"
+ " body sid = %u, offset %" G_GUINT64_FORMAT "\n"
+ " operational pattern = %s\n"
+ " number of essence containers = %u",
+ (pack->type == MXF_PARTITION_PACK_HEADER) ? "header" : (pack->type ==
+ MXF_PARTITION_PACK_BODY) ? "body" : "footer",
+ (pack->closed) ? "yes" : "no", (pack->complete) ? "yes" : "no",
+ pack->major_version, pack->minor_version, pack->kag_size,
+ pack->this_partition, pack->prev_partition, pack->footer_partition,
+ pack->header_byte_count, pack->index_sid, pack->index_byte_count,
+ pack->body_sid, pack->body_offset,
+ mxf_ul_to_string (&pack->operational_pattern, str),
+ pack->n_essence_containers);
+
+ for (i = 0; i < pack->n_essence_containers; i++) {
+ GST_DEBUG (" essence container %d = %s", i,
+ mxf_ul_to_string (&pack->essence_containers[i], str));
+ }
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid partition pack");
+
+ mxf_partition_pack_reset (pack);
+ return FALSE;
+}
+
+void
+mxf_partition_pack_reset (MXFPartitionPack * pack)
+{
+ g_return_if_fail (pack != NULL);
+
+ g_free (pack->essence_containers);
+
+ memset (pack, 0, sizeof (MXFPartitionPack));
+}
+
+/* SMPTE 377M 8.2 Table 1 and 2 */
+
+static void
+_mxf_mapping_ul_free (MXFUL * ul)
+{
+ g_slice_free (MXFUL, ul);
+}
+
+gboolean
+mxf_primer_pack_parse (const MXFUL * key, MXFPrimerPack * pack,
+ const guint8 * data, gsize size)
+{
+ gint i;
+ guint32 n;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (size >= 8, FALSE);
+
+ memset (pack, 0, sizeof (MXFPrimerPack));
+
+ pack->mappings =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ (GDestroyNotify) NULL, (GDestroyNotify) _mxf_mapping_ul_free);
+
+ n = GST_READ_UINT32_BE (data);
+ data += 4;
+
+ if (GST_READ_UINT32_BE (data) != 18)
+ goto error;
+ data += 4;
+
+ if (size < 8 + n * 18)
+ goto error;
+
+ GST_DEBUG ("Parsed primer pack:");
+ for (i = 0; i < n; i++) {
+ guint local_tag;
+ gchar str[48];
+ MXFUL *uid;
+
+ local_tag = GST_READ_UINT16_BE (data);
+ data += 2;
+
+ if (g_hash_table_lookup (pack->mappings, GUINT_TO_POINTER (local_tag)))
+ continue;
+
+ uid = g_slice_new (MXFUL);
+ memcpy (uid, data, 16);
+ data += 16;
+
+ g_hash_table_insert (pack->mappings, GUINT_TO_POINTER (local_tag), uid);
+ GST_DEBUG (" Adding primer pack association: 0x%04x -> %s", local_tag,
+ mxf_ul_to_string (uid, str));
+ }
+
+ pack->valid = TRUE;
+
+ return TRUE;
+
+error:
+ GST_DEBUG ("Invalid primer pack");
+ mxf_primer_pack_reset (pack);
+ return FALSE;
+}
+
+void
+mxf_primer_pack_reset (MXFPrimerPack * pack)
+{
+ g_return_if_fail (pack != NULL);
+
+ if (pack->mappings)
+ g_hash_table_destroy (pack->mappings);
+ memset (pack, 0, sizeof (MXFPrimerPack));
+}
+
+/* structural metadata parsing */
+
+gboolean
+mxf_local_tag_parse (const guint8 * data, gsize size, guint16 * tag,
+ guint16 * tag_size, const guint8 ** tag_data)
+{
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ if (size < 4)
+ return FALSE;
+
+ *tag = GST_READ_UINT16_BE (data);
+ *tag_size = GST_READ_UINT16_BE (data + 2);
+
+ if (size < 4 + *tag_size)
+ return FALSE;
+
+ *tag_data = data + 4;
+
+ return TRUE;
+}
+
+void
+gst_mxf_local_tag_free (MXFLocalTag * tag)
+{
+ g_free (tag->data);
+ g_slice_free (MXFLocalTag, tag);
+}
+
+gboolean
+gst_metadata_add_custom_tag (const MXFPrimerPack * primer,
+ guint16 tag, const guint8 * tag_data, guint16 tag_size,
+ GHashTable ** hash_table)
+{
+ MXFLocalTag *local_tag;
+ MXFUL *key;
+
+ g_return_val_if_fail (primer != NULL, FALSE);
+ g_return_val_if_fail (tag_data != NULL, FALSE);
+ g_return_val_if_fail (hash_table != NULL, FALSE);
+ g_return_val_if_fail (primer->mappings != NULL, FALSE);
+
+ if (*hash_table == NULL)
+ *hash_table =
+ g_hash_table_new_full ((GHashFunc) gst_mxf_ul_hash,
+ (GEqualFunc) gst_mxf_ul_equal, (GDestroyNotify) NULL,
+ (GDestroyNotify) gst_mxf_local_tag_free);
+
+ g_return_val_if_fail (*hash_table != NULL, FALSE);
+
+ key = (MXFUL *) g_hash_table_lookup (primer->mappings,
+ GUINT_TO_POINTER (((guint) tag)));
+
+ if (key) {
+ gchar str[48];
+
+ GST_DEBUG ("Adding local tag 0x%04x with UL %s and size %u", tag,
+ mxf_ul_to_string (key, str), tag_size);
+
+ local_tag = g_slice_new (MXFLocalTag);
+ memcpy (&local_tag->key, key, sizeof (MXFUL));
+ local_tag->size = tag_size;
+ local_tag->data = g_memdup (tag_data, tag_size);
+
+ g_hash_table_insert (*hash_table, &local_tag->key, local_tag);
+ } else {
+ GST_WARNING ("Local tag with no entry in primer pack: 0x%04x", tag);
+ }
+
+ return TRUE;
+}
+
+/* All following defined in SMPTE 377M Annex A, B, C, D */
+gboolean
+mxf_metadata_preface_parse (const MXFUL * key,
+ MXFMetadataPreface * preface, const MXFPrimerPack * primer,
+ const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+ gint i;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (preface, 0, sizeof (MXFMetadataPreface));
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&preface->instance_uid, tag_data, 16);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&preface->generation_uid, tag_data, 16);
+ break;
+ case 0x3b02:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!mxf_timestamp_parse (&preface->last_modified_date, tag_data,
+ tag_size))
+ goto error;
+ break;
+ case 0x3b05:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 2)
+ goto error;
+ preface->version = GST_READ_UINT16_BE (tag_data);
+ break;
+ case 0x3b07:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ preface->object_model_version = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3b08:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&preface->primary_package_uid, tag_data, 16);
+ break;
+ case 0x3b06:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ if (tag_size < 8)
+ goto error;
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ break;
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+ if (tag_size < 8 + len * 16)
+ goto error;
+
+ preface->n_identifications = len;
+ preface->identifications_uids = g_new (MXFUL, len);
+ for (i = 0; i < len; i++)
+ memcpy (&preface->identifications_uids[i], tag_data + 8 + i * 16, 16);
+ break;
+ }
+ case 0x3b03:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&preface->content_storage_uid, tag_data, 16);
+ break;
+ case 0x3b09:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&preface->operational_pattern, tag_data, 16);
+ break;
+ case 0x3b0a:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ if (tag_size < 8)
+ goto error;
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ break;
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+ if (tag_size < 8 + len * 16)
+ goto error;
+
+ preface->n_essence_containers = len;
+ preface->essence_containers = g_new (MXFUL, len);
+ for (i = 0; i < len; i++)
+ memcpy (&preface->essence_containers[i], tag_data + 8 + i * 16, 16);
+ break;
+ }
+ case 0x3b0b:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ if (tag_size < 8)
+ goto error;
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ break;
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+ if (tag_size < 8 + len * 16)
+ goto error;
+
+ preface->n_dm_schemes = len;
+ preface->dm_schemes = g_new (MXFUL, len);
+ for (i = 0; i < len; i++)
+ memcpy (&preface->dm_schemes[i], tag_data + 8 + i * 16, 16);
+ break;
+ }
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &preface->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed preface:");
+ GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&preface->instance_uid,
+ str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&preface->generation_uid, str));
+ GST_DEBUG (" last modified date = %d/%u/%u %u:%u:%u.%u",
+ preface->last_modified_date.year, preface->last_modified_date.month,
+ preface->last_modified_date.day, preface->last_modified_date.hour,
+ preface->last_modified_date.minute, preface->last_modified_date.second,
+ (preface->last_modified_date.quarter_msecond * 1000) / 256);
+ GST_DEBUG (" version = %u.%u", (preface->version >> 8),
+ (preface->version & 0x0f));
+ GST_DEBUG (" object model version = %u", preface->object_model_version);
+ GST_DEBUG (" primary package = %s",
+ mxf_ul_to_string (&preface->primary_package_uid, str));
+ GST_DEBUG (" content storage = %s",
+ mxf_ul_to_string (&preface->content_storage_uid, str));
+ GST_DEBUG (" operational pattern = %s",
+ mxf_ul_to_string (&preface->operational_pattern, str));
+ GST_DEBUG (" number of identifications = %u", preface->n_identifications);
+ GST_DEBUG (" number of essence containers = %u",
+ preface->n_essence_containers);
+ GST_DEBUG (" number of DM schemes = %u", preface->n_dm_schemes);
+
+ for (i = 0; i < preface->n_identifications; i++)
+ GST_DEBUG (" identification %d = %s", i,
+ mxf_ul_to_string (&preface->identifications_uids[i], str));
+
+ for (i = 0; i < preface->n_essence_containers; i++)
+ GST_DEBUG (" essence container %d = %s", i,
+ mxf_ul_to_string (&preface->essence_containers[i], str));
+
+ for (i = 0; i < preface->n_dm_schemes; i++)
+ GST_DEBUG (" DM schemes %d = %s", i,
+ mxf_ul_to_string (&preface->dm_schemes[i], str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid preface");
+ mxf_metadata_preface_reset (preface);
+
+ return FALSE;
+}
+
+void
+mxf_metadata_preface_reset (MXFMetadataPreface * preface)
+{
+ g_return_if_fail (preface != NULL);
+
+ g_free (preface->identifications_uids);
+ g_free (preface->identifications);
+ g_free (preface->essence_containers);
+ g_free (preface->dm_schemes);
+
+ if (preface->other_tags)
+ g_hash_table_destroy (preface->other_tags);
+
+ memset (preface, 0, sizeof (MXFMetadataPreface));
+}
+
+gboolean
+mxf_metadata_identification_parse (const MXFUL * key,
+ MXFMetadataIdentification * identification,
+ const MXFPrimerPack * primer, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (identification, 0, sizeof (MXFMetadataIdentification));
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&identification->instance_uid, tag_data, 16);
+ break;
+ case 0x3c09:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&identification->generation_uid, tag_data, 16);
+ break;
+ case 0x3c01:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ identification->company_name = mxf_utf16_to_utf8 (tag_data, tag_size);
+ break;
+ case 0x3c02:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ identification->product_name = mxf_utf16_to_utf8 (tag_data, tag_size);
+ break;
+ case 0x3c03:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 10)
+ goto error;
+ if (!mxf_product_version_parse (&identification->product_version,
+ tag_data, tag_size))
+ goto error;
+ break;
+ case 0x3c04:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ identification->version_string = mxf_utf16_to_utf8 (tag_data, tag_size);
+ break;
+ case 0x3c05:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&identification->product_uid, tag_data, 16);
+ break;
+ case 0x3c06:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ if (!mxf_timestamp_parse (&identification->modification_date, tag_data,
+ tag_size))
+ goto error;
+ break;
+ case 0x3c07:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 10)
+ goto error;
+ if (!mxf_product_version_parse (&identification->toolkit_version,
+ tag_data, tag_size))
+ goto error;
+ break;
+ case 0x3c08:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ identification->platform = mxf_utf16_to_utf8 (tag_data, tag_size);
+ break;
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &identification->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed identification:");
+ GST_DEBUG (" instance uid = %s",
+ mxf_ul_to_string (&identification->instance_uid, str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&identification->generation_uid, str));
+ GST_DEBUG (" company name = %s",
+ GST_STR_NULL (identification->company_name));
+ GST_DEBUG (" product version = %u.%u.%u.%u.%u",
+ identification->product_version.major,
+ identification->product_version.minor,
+ identification->product_version.patch,
+ identification->product_version.build,
+ identification->product_version.release);
+ GST_DEBUG (" version string = %s",
+ GST_STR_NULL (identification->version_string));
+ GST_DEBUG (" product uid = %s",
+ mxf_ul_to_string (&identification->product_uid, str));
+ GST_DEBUG (" modification date = %d/%u/%u %u:%u:%u.%u",
+ identification->modification_date.year,
+ identification->modification_date.month,
+ identification->modification_date.day,
+ identification->modification_date.hour,
+ identification->modification_date.minute,
+ identification->modification_date.second,
+ (identification->modification_date.quarter_msecond * 1000) / 256);
+ GST_DEBUG (" toolkit version = %u.%u.%u.%u.%u",
+ identification->toolkit_version.major,
+ identification->toolkit_version.minor,
+ identification->toolkit_version.patch,
+ identification->toolkit_version.build,
+ identification->toolkit_version.release);
+ GST_DEBUG (" platform = %s", GST_STR_NULL (identification->platform));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid identification");
+ mxf_metadata_identification_reset (identification);
+
+ return FALSE;
+}
+
+void mxf_metadata_identification_reset
+ (MXFMetadataIdentification * identification)
+{
+ g_return_if_fail (identification != NULL);
+
+ g_free (identification->company_name);
+ g_free (identification->product_name);
+ g_free (identification->version_string);
+ g_free (identification->platform);
+
+ if (identification->other_tags)
+ g_hash_table_destroy (identification->other_tags);
+
+ memset (identification, 0, sizeof (MXFMetadataIdentification));
+}
+
+gboolean
+mxf_metadata_content_storage_parse (const MXFUL * key,
+ MXFMetadataContentStorage * content_storage,
+ const MXFPrimerPack * primer, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+ gint i;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (content_storage, 0, sizeof (MXFMetadataContentStorage));
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&content_storage->instance_uid, tag_data, 16);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&content_storage->generation_uid, tag_data, 16);
+ break;
+ case 0x1901:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ break;
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+ if (tag_size < 8 + len * 16)
+ goto error;
+
+ content_storage->packages_uids = g_new (MXFUL, len);
+ content_storage->n_packages = len;
+ for (i = 0; i < len; i++)
+ memcpy (&content_storage->packages_uids[i], tag_data + 8 + i * 16,
+ 16);
+ break;
+ }
+ case 0x1902:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ break;
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+ if (tag_size < 8 + len * 16)
+ goto error;
+
+ content_storage->essence_container_data_uids = g_new (MXFUL, len);
+ content_storage->n_essence_container_data = len;
+ for (i = 0; i < len; i++)
+ memcpy (&content_storage->essence_container_data_uids[i],
+ tag_data + 8 + i * 16, 16);
+ break;
+ }
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &content_storage->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed content storage:");
+ GST_DEBUG (" instance uid = %s",
+ mxf_ul_to_string (&content_storage->instance_uid, str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&content_storage->generation_uid, str));
+ GST_DEBUG (" number of packages = %u", content_storage->n_packages);
+ GST_DEBUG (" number of essence container data = %u",
+ content_storage->n_essence_container_data);
+
+ for (i = 0; i < content_storage->n_packages; i++)
+ GST_DEBUG (" package %i = %s", i,
+ mxf_ul_to_string (&content_storage->packages_uids[i], str));
+ for (i = 0; i < content_storage->n_packages; i++)
+ GST_DEBUG (" essence container data %i = %s", i,
+ mxf_ul_to_string (&content_storage->essence_container_data_uids[i],
+ str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid content storage");
+ mxf_metadata_content_storage_reset (content_storage);
+
+ return FALSE;
+}
+
+void mxf_metadata_content_storage_reset
+ (MXFMetadataContentStorage * content_storage)
+{
+ g_return_if_fail (content_storage != NULL);
+
+ g_free (content_storage->packages);
+ g_free (content_storage->packages_uids);
+ g_free (content_storage->essence_container_data);
+ g_free (content_storage->essence_container_data_uids);
+
+ if (content_storage->other_tags)
+ g_hash_table_destroy (content_storage->other_tags);
+
+ memset (content_storage, 0, sizeof (MXFMetadataContentStorage));
+}
+
+gboolean
+mxf_metadata_essence_container_data_parse (const MXFUL * key,
+ MXFMetadataEssenceContainerData * essence_container_data,
+ const MXFPrimerPack * primer, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[96];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (essence_container_data, 0, sizeof (MXFMetadataEssenceContainerData));
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&essence_container_data->instance_uid, tag_data, 16);
+ break;
+ case 0x2701:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 32)
+ goto error;
+ memcpy (&essence_container_data->linked_package_uid, tag_data, 32);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&essence_container_data->generation_uid, tag_data, 16);
+ break;
+ case 0x3f06:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ essence_container_data->index_sid = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3f07:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ essence_container_data->body_sid = GST_READ_UINT32_BE (tag_data);
+ break;
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &essence_container_data->other_tags))
+ goto error;
+ break;
+ }
+ next:
+
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed essence container data:");
+ GST_DEBUG (" instance uid = %s",
+ mxf_ul_to_string (&essence_container_data->instance_uid, str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&essence_container_data->generation_uid, str));
+ GST_DEBUG (" linked package = %s",
+ mxf_umid_to_string (&essence_container_data->linked_package_uid, str));
+ GST_DEBUG (" index sid = %u", essence_container_data->index_sid);
+ GST_DEBUG (" body sid = %u", essence_container_data->body_sid);
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid essence container data");
+ mxf_metadata_essence_container_data_reset (essence_container_data);
+
+ return FALSE;
+}
+
+void mxf_metadata_essence_container_data_reset
+ (MXFMetadataEssenceContainerData * essence_container_data)
+{
+ g_return_if_fail (essence_container_data != NULL);
+
+ if (essence_container_data->other_tags)
+ g_hash_table_destroy (essence_container_data->other_tags);
+
+ memset (essence_container_data, 0, sizeof (MXFMetadataEssenceContainerData));
+}
+
+gboolean
+mxf_metadata_generic_package_parse (const MXFUL * key,
+ MXFMetadataGenericPackage * generic_package,
+ const MXFPrimerPack * primer, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[96];
+ gint i;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (generic_package, 0, sizeof (MXFMetadataGenericPackage));
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&generic_package->instance_uid, tag_data, 16);
+ break;
+ case 0x4401:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 32)
+ goto error;
+ memcpy (&generic_package->package_uid, tag_data, 32);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&generic_package->generation_uid, tag_data, 16);
+ break;
+ case 0x4402:
+ generic_package->name = mxf_utf16_to_utf8 (tag_data, tag_size);
+ break;
+ case 0x4405:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!mxf_timestamp_parse (&generic_package->package_creation_date,
+ tag_data, tag_size))
+ goto error;
+ break;
+ case 0x4404:
+ if (!mxf_timestamp_parse (&generic_package->package_modified_date,
+ tag_data, tag_size))
+ goto error;
+ break;
+ case 0x4403:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ break;
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+ if (tag_size < 8 + len * 16)
+ goto error;
+
+ generic_package->tracks_uids = g_new (MXFUL, len);
+ generic_package->n_tracks = len;
+ for (i = 0; i < len; i++)
+ memcpy (&generic_package->tracks_uids[i], tag_data + 8 + i * 16, 16);
+ break;
+ }
+ case 0x4701:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+
+ generic_package->n_descriptors = 1;
+ memcpy (&generic_package->descriptors_uid, tag_data, 16);
+ break;
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &generic_package->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed package:");
+ GST_DEBUG (" instance uid = %s",
+ mxf_ul_to_string (&generic_package->instance_uid, str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&generic_package->generation_uid, str));
+ GST_DEBUG (" UMID = %s", mxf_umid_to_string (&generic_package->package_uid,
+ str));
+ GST_DEBUG (" name = %s", GST_STR_NULL (generic_package->name));
+ GST_DEBUG (" creation date = %d/%u/%u %u:%u:%u.%u",
+ generic_package->package_creation_date.year,
+ generic_package->package_creation_date.month,
+ generic_package->package_creation_date.day,
+ generic_package->package_creation_date.hour,
+ generic_package->package_creation_date.minute,
+ generic_package->package_creation_date.second,
+ (generic_package->package_creation_date.quarter_msecond * 1000) / 256);
+ GST_DEBUG (" modification date = %d/%u/%u %u:%u:%u.%u",
+ generic_package->package_modified_date.year,
+ generic_package->package_modified_date.month,
+ generic_package->package_modified_date.day,
+ generic_package->package_modified_date.hour,
+ generic_package->package_modified_date.minute,
+ generic_package->package_modified_date.second,
+ (generic_package->package_modified_date.quarter_msecond * 1000) / 256);
+ GST_DEBUG (" descriptor = %s",
+ mxf_ul_to_string (&generic_package->descriptors_uid, str));
+ GST_DEBUG (" number of tracks = %u", generic_package->n_tracks);
+
+ for (i = 0; i < generic_package->n_tracks; i++)
+ GST_DEBUG (" track %d = %s", i,
+ mxf_ul_to_string (&generic_package->tracks_uids[i], str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid package");
+ mxf_metadata_generic_package_reset (generic_package);
+
+ return FALSE;
+}
+
+void mxf_metadata_generic_package_reset
+ (MXFMetadataGenericPackage * generic_package)
+{
+ g_return_if_fail (generic_package != NULL);
+
+ g_free (generic_package->name);
+ g_free (generic_package->tracks_uids);
+
+ g_free (generic_package->tracks);
+
+ if (generic_package->other_tags)
+ g_hash_table_destroy (generic_package->other_tags);
+
+ g_free (generic_package->descriptors);
+
+ memset (generic_package, 0, sizeof (MXFMetadataGenericPackage));
+}
+
+gboolean
+mxf_metadata_track_parse (const MXFUL * key,
+ MXFMetadataTrack * track, const MXFPrimerPack * primer,
+ const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (track, 0, sizeof (MXFMetadataTrack));
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&track->instance_uid, tag_data, 16);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&track->generation_uid, tag_data, 16);
+ break;
+ case 0x4801:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ track->track_id = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x4804:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ track->track_number = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x4802:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ track->track_name = mxf_utf16_to_utf8 (tag_data, tag_size);
+ break;
+ case 0x4b01:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!mxf_fraction_parse (&track->edit_rate, tag_data, tag_size))
+ goto error;
+ break;
+ case 0x4b02:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ track->origin = GST_READ_UINT64_BE (tag_data);
+ break;
+ case 0x4803:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&track->sequence_uid, tag_data, 16);
+ break;
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &track->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed track:");
+ GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&track->instance_uid,
+ str));
+ GST_DEBUG (" generation uid = %s", mxf_ul_to_string (&track->generation_uid,
+ str));
+ GST_DEBUG (" track id = %u", track->track_id);
+ GST_DEBUG (" track number = %u", track->track_number);
+ GST_DEBUG (" track name = %s", GST_STR_NULL (track->track_name));
+ GST_DEBUG (" edit rate = %d/%d", track->edit_rate.n, track->edit_rate.d);
+ GST_DEBUG (" origin = %" G_GINT64_FORMAT, track->origin);
+ GST_DEBUG (" sequence uid = %s", mxf_ul_to_string (&track->sequence_uid,
+ str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid track");
+ mxf_metadata_track_reset (track);
+
+ return FALSE;
+}
+
+void
+mxf_metadata_track_reset (MXFMetadataTrack * track)
+{
+ g_return_if_fail (track != NULL);
+
+ g_free (track->track_name);
+
+ if (track->descriptor)
+ g_free (track->descriptor);
+
+ if (track->other_tags)
+ g_hash_table_destroy (track->other_tags);
+
+ memset (track, 0, sizeof (MXFMetadataTrack));
+}
+
+/* SMPTE RP224 */
+static const struct
+{
+ guint8 ul[16];
+ MXFMetadataTrackType type;
+} mxf_metadata_track_identifier[] = {
+ { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01,
+ 0x01, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00},
+ MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x01,
+ 0x02, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_TIMECODE_12M_ACTIVE}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x01,
+ 0x03, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_TIMECODE_309M}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x01,
+ 0x10, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_METADATA}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02,
+ 0x01, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_PICTURE_ESSENCE}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02,
+ 0x02, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_SOUND_ESSENCE}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02,
+ 0x03, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_DATA_ESSENCE}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03,
+ 0x01, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_AUXILIARY_DATA}, { {
+ 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03,
+ 0x02, 0x00, 0x00, 0x00}, MXF_METADATA_TRACK_PARSED_TEXT}
+};
+
+MXFMetadataTrackType
+mxf_metadata_track_identifier_parse (const MXFUL * track_identifier)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (mxf_metadata_track_identifier); i++)
+ if (memcmp (&mxf_metadata_track_identifier[i].ul, &track_identifier->u,
+ 16) == 0)
+ return mxf_metadata_track_identifier[i].type;
+
+ return MXF_METADATA_TRACK_UNKNOWN;
+}
+
+gboolean
+mxf_metadata_sequence_parse (const MXFUL * key,
+ MXFMetadataSequence * sequence, const MXFPrimerPack * primer,
+ const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+ gint i;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (sequence, 0, sizeof (MXFMetadataSequence));
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&sequence->instance_uid, tag_data, 16);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&sequence->generation_uid, tag_data, 16);
+ break;
+ case 0x0201:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&sequence->data_definition, tag_data, 16);
+ break;
+ case 0x0202:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ sequence->duration = GST_READ_UINT64_BE (tag_data);
+ break;
+ case 0x1001:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ break;
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+ if (tag_size < 8 + len * 16)
+ goto error;
+
+ sequence->structural_components_uids = g_new (MXFUL, len);
+ sequence->n_structural_components = len;
+ for (i = 0; i < len; i++)
+ memcpy (&sequence->structural_components_uids[i],
+ tag_data + 8 + i * 16, 16);
+ break;
+ }
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &sequence->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed sequence:");
+ GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&sequence->instance_uid,
+ str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&sequence->generation_uid, str));
+ GST_DEBUG (" data definition = %s",
+ mxf_ul_to_string (&sequence->data_definition, str));
+ GST_DEBUG (" duration = %" G_GINT64_FORMAT, sequence->duration);
+ GST_DEBUG (" number of structural components = %u",
+ sequence->n_structural_components);
+
+ for (i = 0; i < sequence->n_structural_components; i++)
+ GST_DEBUG (" structural component %d = %s", i,
+ mxf_ul_to_string (&sequence->structural_components_uids[i], str));
+
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid sequence");
+ mxf_metadata_sequence_reset (sequence);
+
+ return FALSE;
+}
+
+void
+mxf_metadata_sequence_reset (MXFMetadataSequence * sequence)
+{
+ g_return_if_fail (sequence != NULL);
+
+ g_free (sequence->structural_components_uids);
+ g_free (sequence->structural_components);
+
+ if (sequence->other_tags)
+ g_hash_table_destroy (sequence->other_tags);
+
+ memset (sequence, 0, sizeof (MXFMetadataSequence));
+}
+
+gboolean
+mxf_metadata_structural_component_parse (const MXFUL * key,
+ MXFMetadataStructuralComponent * component,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[96];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (component, 0, sizeof (MXFMetadataStructuralComponent));
+
+ component->type = type;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&component->instance_uid, tag_data, 16);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&component->generation_uid, tag_data, 16);
+ break;
+ case 0x0201:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&component->data_definition, tag_data, 16);
+ break;
+ case 0x0202:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ component->duration = GST_READ_UINT64_BE (tag_data);
+ break;
+ /* Timecode component specifics */
+ case 0x1502:
+ if (type != MXF_METADATA_TIMECODE_COMPONENT)
+ goto DFLT;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 2)
+ goto error;
+ component->timecode_component.rounded_timecode_base =
+ GST_READ_UINT16_BE (tag_data);
+ break;
+ case 0x1501:
+ if (type != MXF_METADATA_TIMECODE_COMPONENT)
+ goto DFLT;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ component->timecode_component.start_timecode =
+ GST_READ_UINT64_BE (tag_data);
+ break;
+ case 0x1503:
+ if (type != MXF_METADATA_TIMECODE_COMPONENT)
+ goto DFLT;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ component->timecode_component.drop_frame =
+ (GST_READ_UINT8 (tag_data) != 0);
+ break;
+ /* Source clip specifics */
+ case 0x1201:
+ if (type != MXF_METADATA_SOURCE_CLIP)
+ goto DFLT;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ component->source_clip.start_position = GST_READ_UINT64_BE (tag_data);
+ break;
+ case 0x1101:
+ if (type != MXF_METADATA_SOURCE_CLIP)
+ goto DFLT;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 32)
+ goto error;
+ memcpy (&component->source_clip.source_package_id, tag_data, 32);
+ break;
+ case 0x1102:
+ if (type != MXF_METADATA_SOURCE_CLIP)
+ goto DFLT;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ component->source_clip.source_track_id = GST_READ_UINT32_BE (tag_data);
+ break;
+ DFLT:
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &component->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed structural component:");
+ GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&component->instance_uid,
+ str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&component->generation_uid, str));
+ GST_DEBUG (" type = %s",
+ (component->type ==
+ MXF_METADATA_TIMECODE_COMPONENT) ? "timecode component" :
+ "source clip");
+ GST_DEBUG (" data definition = %s",
+ mxf_ul_to_string (&component->data_definition, str));
+ GST_DEBUG (" duration = %" G_GINT64_FORMAT, component->duration);
+
+ if (component->type == MXF_METADATA_TIMECODE_COMPONENT) {
+ GST_DEBUG (" start timecode = %" G_GINT64_FORMAT,
+ component->timecode_component.start_timecode);
+ GST_DEBUG (" rounded timecode base = %u",
+ component->timecode_component.rounded_timecode_base);
+ GST_DEBUG (" drop frame = %s",
+ (component->timecode_component.drop_frame) ? "yes" : "no");
+ } else {
+ GST_DEBUG (" start position = %" G_GINT64_FORMAT,
+ component->source_clip.start_position);
+ GST_DEBUG (" source package id = %s",
+ mxf_umid_to_string (&component->source_clip.source_package_id, str));
+ GST_DEBUG (" source track id = %u",
+ component->source_clip.source_track_id);
+ }
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid structural component");
+ mxf_metadata_structural_component_reset (component);
+
+ return FALSE;
+}
+
+void mxf_metadata_structural_component_reset
+ (MXFMetadataStructuralComponent * component)
+{
+ g_return_if_fail (component != NULL);
+
+ if (component->other_tags)
+ g_hash_table_destroy (component->other_tags);
+
+ memset (component, 0, sizeof (MXFMetadataStructuralComponent));
+}
+
+gboolean
+mxf_metadata_generic_descriptor_parse (const MXFUL * key,
+ MXFMetadataGenericDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+ gint i;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataGenericDescriptor));
+
+ descriptor->type = type;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->instance_uid, tag_data, 16);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->generation_uid, tag_data, 16);
+ break;
+ case 0x2f01:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size < 8)
+ goto error;
+
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ goto next;
+
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+
+ descriptor->locators_uids = g_new (MXFUL, len);
+ descriptor->n_locators = len;
+ for (i = 0; i < len; i++)
+ memcpy (&descriptor->locators_uids[i], tag_data + 8 + i * 16, 16);
+ break;
+ }
+ }
+ next:
+
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed generic descriptor:");
+ GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&descriptor->instance_uid,
+ str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&descriptor->generation_uid, str));
+ GST_DEBUG (" type = %u", descriptor->type);
+ GST_DEBUG (" number of locators = %u", descriptor->n_locators);
+
+ for (i = 0; i < descriptor->n_locators; i++)
+ GST_DEBUG (" locator %d = %s", i,
+ mxf_ul_to_string (&descriptor->locators_uids[i], str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid generic descriptor");
+ mxf_metadata_generic_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void mxf_metadata_generic_descriptor_reset
+ (MXFMetadataGenericDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ switch (descriptor->type) {
+ case MXF_METADATA_FILE_DESCRIPTOR:
+ break;
+ }
+
+ if (descriptor->locators_uids)
+ g_free (descriptor->locators_uids);
+
+ if (descriptor->locators)
+ g_free (descriptor->locators);
+
+ if (descriptor->other_tags)
+ g_hash_table_destroy (descriptor->other_tags);
+
+ memset (descriptor, 0, sizeof (MXFMetadataGenericDescriptor));
+}
+
+gboolean
+mxf_metadata_file_descriptor_parse (const MXFUL * key,
+ MXFMetadataFileDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataFileDescriptor));
+
+ if (!mxf_metadata_generic_descriptor_parse (key,
+ (MXFMetadataGenericDescriptor *) descriptor, primer, type, data,
+ size))
+ goto error;
+
+ descriptor->parent.is_file_descriptor = TRUE;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3006:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->linked_track_id = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3001:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!mxf_fraction_parse (&descriptor->sample_rate, tag_data, tag_size))
+ goto error;
+ break;
+ case 0x3002:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 8)
+ goto error;
+ descriptor->container_duration = GST_READ_UINT64_BE (tag_data);
+ break;
+ case 0x3004:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->essence_container, tag_data, 16);
+ break;
+ case 0x3005:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->codec, tag_data, 16);
+ break;
+ default:
+ if (type != MXF_METADATA_FILE_DESCRIPTOR)
+ goto next;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed file descriptor:");
+ GST_DEBUG (" linked track id = %u", descriptor->linked_track_id);
+ GST_DEBUG (" sample rate = %d/%d", descriptor->sample_rate.n,
+ descriptor->sample_rate.d);
+ GST_DEBUG (" container duration = %" G_GINT64_FORMAT,
+ descriptor->container_duration);
+ GST_DEBUG (" essence container = %s",
+ mxf_ul_to_string (&descriptor->essence_container, str));
+ GST_DEBUG (" codec = %s", mxf_ul_to_string (&descriptor->codec, str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid file descriptor");
+ mxf_metadata_file_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void
+mxf_metadata_file_descriptor_reset (MXFMetadataFileDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ mxf_metadata_generic_descriptor_reset ((MXFMetadataGenericDescriptor *)
+ descriptor);
+
+ memset (descriptor, 0, sizeof (MXFMetadataFileDescriptor));
+}
+
+gboolean
+mxf_metadata_generic_sound_essence_descriptor_parse (const MXFUL * key,
+ MXFMetadataGenericSoundEssenceDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataGenericSoundEssenceDescriptor));
+
+ if (!mxf_metadata_file_descriptor_parse (key,
+ (MXFMetadataFileDescriptor *) descriptor, primer, type, data, size))
+ goto error;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3d03:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!mxf_fraction_parse (&descriptor->audio_sampling_rate, tag_data,
+ tag_size))
+ goto error;
+ break;
+ case 0x3d02:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->locked = (GST_READ_UINT8 (tag_data) != 0);
+ break;
+ case 0x3d04:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->audio_ref_level = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3d05:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->electro_spatial_formulation = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3d07:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->channel_count = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d01:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->quantization_bits = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3d0c:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->dial_norm = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3d06:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->sound_essence_compression, tag_data, 16);
+ break;
+ default:
+ if (type != MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR)
+ goto next;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed generic sound essence descriptor:");
+ GST_DEBUG (" audio sampling rate = %d/%d", descriptor->audio_sampling_rate.n,
+ descriptor->audio_sampling_rate.d);
+ GST_DEBUG (" locked = %s", (descriptor->locked) ? "yes" : "no");
+ GST_DEBUG (" audio ref level = %d", descriptor->audio_ref_level);
+ GST_DEBUG (" electro spatial formulation = %u",
+ descriptor->electro_spatial_formulation);
+ GST_DEBUG (" channel count = %u", descriptor->channel_count);
+ GST_DEBUG (" quantization bits = %u", descriptor->quantization_bits);
+ GST_DEBUG (" dial norm = %d", descriptor->dial_norm);
+ GST_DEBUG (" sound essence compression = %s",
+ mxf_ul_to_string (&descriptor->sound_essence_compression, str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid generic sound essence descriptor");
+ mxf_metadata_generic_sound_essence_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void mxf_metadata_generic_sound_essence_descriptor_reset
+ (MXFMetadataGenericSoundEssenceDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ mxf_metadata_file_descriptor_reset ((MXFMetadataFileDescriptor *) descriptor);
+
+ memset (descriptor, 0, sizeof (MXFMetadataGenericSoundEssenceDescriptor));
+}
+
+gboolean
+mxf_metadata_generic_picture_essence_descriptor_parse (const MXFUL * key,
+ MXFMetadataGenericPictureEssenceDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataGenericPictureEssenceDescriptor));
+
+ if (!mxf_metadata_file_descriptor_parse (key,
+ (MXFMetadataFileDescriptor *) descriptor, primer, type, data, size))
+ goto error;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3215:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->signal_standard = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x320c:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->frame_layout = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3203:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->stored_width = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3202:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->stored_height = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3216:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->stored_f2_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3205:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->sampled_width = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3204:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->sampled_height = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3206:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->sampled_x_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3207:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->sampled_y_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3208:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->display_height = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3209:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->display_width = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x320a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->display_x_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x320b:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->display_y_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3217:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->display_f2_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x320e:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!mxf_fraction_parse (&descriptor->aspect_ratio, tag_data, tag_size))
+ goto error;
+ break;
+ case 0x3218:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->active_format_descriptor = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x320d:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size < 8)
+ goto error;
+
+ if (GST_READ_UINT32_BE (tag_data) == 0)
+ goto next;
+
+ if (GST_READ_UINT32_BE (tag_data) != 2 &&
+ GST_READ_UINT32_BE (tag_data + 4) != 4)
+ goto error;
+
+ if (tag_size != 16)
+ goto error;
+
+ descriptor->video_line_map[0] = GST_READ_UINT32_BE (tag_data + 8);
+ descriptor->video_line_map[1] = GST_READ_UINT32_BE (tag_data + 12);
+ break;
+ case 0x320f:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->alpha_transparency = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3210:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->capture_gamma, tag_data, 16);
+ break;
+ case 0x3211:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->image_alignment_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3213:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->image_start_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3214:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->image_end_offset = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3212:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->field_dominance = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3201:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&descriptor->picture_essence_coding, tag_data, 16);
+ break;
+ default:
+ if (type != MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR)
+ goto next;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed generic picture essence descriptor:");
+ GST_DEBUG (" signal standard = %u", descriptor->signal_standard);
+ GST_DEBUG (" frame layout = %u", descriptor->frame_layout);
+ GST_DEBUG (" stored size = %ux%u (f2 = %d)", descriptor->stored_width,
+ descriptor->stored_height, descriptor->stored_f2_offset);
+ GST_DEBUG (" sampled size = %ux%u (offset = %d x %d)",
+ descriptor->sampled_width, descriptor->sampled_height,
+ descriptor->sampled_x_offset, descriptor->sampled_y_offset);
+ GST_DEBUG (" display size = %ux%u (f2 = %d, offset = %d x %d)",
+ descriptor->display_height, descriptor->display_width,
+ descriptor->display_x_offset, descriptor->display_y_offset,
+ descriptor->display_f2_offset);
+ GST_DEBUG (" aspect ratio = %d/%d", descriptor->aspect_ratio.n,
+ descriptor->aspect_ratio.d);
+ GST_DEBUG (" active format descriptor = %u",
+ descriptor->active_format_descriptor);
+ GST_DEBUG (" video line map = {%i, %i}", descriptor->video_line_map[0],
+ descriptor->video_line_map[1]);
+ GST_DEBUG (" alpha transparency = %u", descriptor->alpha_transparency);
+ GST_DEBUG (" capture gamma = %s",
+ mxf_ul_to_string (&descriptor->capture_gamma, str));
+ GST_DEBUG (" image alignment offset = %u",
+ descriptor->image_alignment_offset);
+ GST_DEBUG (" image start offset = %u", descriptor->image_start_offset);
+ GST_DEBUG (" image end offset = %u", descriptor->image_end_offset);
+ GST_DEBUG (" field dominance = %u", descriptor->field_dominance);
+ GST_DEBUG (" picture essence coding = %s",
+ mxf_ul_to_string (&descriptor->picture_essence_coding, str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid generic picture essence descriptor");
+ mxf_metadata_generic_picture_essence_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void mxf_metadata_generic_picture_essence_descriptor_reset
+ (MXFMetadataGenericPictureEssenceDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ mxf_metadata_file_descriptor_reset ((MXFMetadataFileDescriptor *) descriptor);
+
+ memset (descriptor, 0, sizeof (MXFMetadataGenericPictureEssenceDescriptor));
+}
+
+gboolean
+mxf_metadata_cdci_picture_essence_descriptor_parse (const MXFUL * key,
+ MXFMetadataCDCIPictureEssenceDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataCDCIPictureEssenceDescriptor));
+
+ if (!mxf_metadata_generic_picture_essence_descriptor_parse (key,
+ (MXFMetadataGenericPictureEssenceDescriptor *) descriptor, primer,
+ type, data, size))
+ goto error;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3301:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->component_depth = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3302:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->horizontal_subsampling = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3308:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->vertical_subsampling = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3303:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->color_siting = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x330b:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 1)
+ goto error;
+ descriptor->reversed_byte_order = GST_READ_UINT8 (tag_data);
+ break;
+ case 0x3307:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 2)
+ goto error;
+ descriptor->padding_bits = GST_READ_UINT16_BE (tag_data);
+ break;
+ case 0x3309:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->alpha_sample_depth = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3304:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->black_ref_level = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3305:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->white_ref_level = GST_READ_UINT32_BE (tag_data);
+ break;
+ case 0x3306:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 4)
+ goto error;
+ descriptor->color_range = GST_READ_UINT32_BE (tag_data);
+ break;
+ default:
+ if (type != MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR)
+ goto next;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed CDCI picture essence descriptor:");
+ GST_DEBUG (" component depth = %u", descriptor->component_depth);
+ GST_DEBUG (" horizontal subsampling = %u",
+ descriptor->horizontal_subsampling);
+ GST_DEBUG (" vertical subsampling = %u", descriptor->vertical_subsampling);
+ GST_DEBUG (" color siting = %u", descriptor->color_siting);
+ GST_DEBUG (" reversed byte order = %s",
+ (descriptor->reversed_byte_order) ? "yes" : "no");
+ GST_DEBUG (" padding bits = %d", descriptor->padding_bits);
+ GST_DEBUG (" alpha sample depth = %u", descriptor->alpha_sample_depth);
+ GST_DEBUG (" black ref level = %u", descriptor->black_ref_level);
+ GST_DEBUG (" white ref level = %u", descriptor->white_ref_level);
+ GST_DEBUG (" color range = %u", descriptor->color_range);
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid CDCI picture essence descriptor");
+ mxf_metadata_cdci_picture_essence_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void mxf_metadata_cdci_picture_essence_descriptor_reset
+ (MXFMetadataCDCIPictureEssenceDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ mxf_metadata_generic_picture_essence_descriptor_reset (
+ (MXFMetadataGenericPictureEssenceDescriptor *) descriptor);
+
+ memset (descriptor, 0, sizeof (MXFMetadataCDCIPictureEssenceDescriptor));
+}
+
+gboolean
+mxf_metadata_multiple_descriptor_parse (const MXFUL * key,
+ MXFMetadataMultipleDescriptor * descriptor,
+ const MXFPrimerPack * primer, guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+ gint i;
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (descriptor, 0, sizeof (MXFMetadataMultipleDescriptor));
+
+ if (!mxf_metadata_file_descriptor_parse (key,
+ (MXFMetadataFileDescriptor *) descriptor, primer, type, data, size))
+ goto error;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3f01:{
+ guint32 len;
+ guint i;
+
+ GST_WRITE_UINT16_BE (data, 0x0000);
+
+ if (tag_size < 8)
+ goto error;
+ len = GST_READ_UINT32_BE (tag_data);
+ if (len == 0)
+ goto next;
+
+ if (GST_READ_UINT32_BE (tag_data + 4) != 16)
+ goto error;
+
+ descriptor->n_sub_descriptors = len;
+ descriptor->sub_descriptors_uids = g_new0 (MXFUL, len);
+ for (i = 0; i < len; i++)
+ memcpy (&descriptor->sub_descriptors_uids[i], tag_data + 8 + i * 16,
+ 16);
+ break;
+ }
+ default:
+ if (type != MXF_METADATA_MULTIPLE_DESCRIPTOR)
+ goto next;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &((MXFMetadataGenericDescriptor *) descriptor)->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed multiple descriptor:");
+ GST_DEBUG (" number of sub descriptors = %u", descriptor->n_sub_descriptors);
+ for (i = 0; i < descriptor->n_sub_descriptors; i++)
+ GST_DEBUG (" sub descriptor %d = %s", i,
+ mxf_ul_to_string (&descriptor->sub_descriptors_uids[i], str));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid multiple descriptor");
+ mxf_metadata_multiple_descriptor_reset (descriptor);
+
+ return FALSE;
+}
+
+void mxf_metadata_multiple_descriptor_reset
+ (MXFMetadataMultipleDescriptor * descriptor)
+{
+ g_return_if_fail (descriptor != NULL);
+
+ g_free (descriptor->sub_descriptors_uids);
+ g_free (descriptor->sub_descriptors);
+
+ mxf_metadata_file_descriptor_reset ((MXFMetadataFileDescriptor *) descriptor);
+
+ memset (descriptor, 0, sizeof (MXFMetadataMultipleDescriptor));
+}
+
+gboolean
+mxf_metadata_locator_parse (const MXFUL * key,
+ MXFMetadataLocator * locator, const MXFPrimerPack * primer,
+ guint16 type, const guint8 * data, gsize size)
+{
+ guint16 tag, tag_size;
+ const guint8 *tag_data;
+ gchar str[48];
+
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ memset (locator, 0, sizeof (MXFMetadataLocator));
+
+ locator->type = type;
+
+ while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
+ if (tag_size == 0 || tag == 0x0000)
+ goto next;
+
+ switch (tag) {
+ case 0x3c0a:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&locator->instance_uid, tag_data, 16);
+ break;
+ case 0x0102:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (tag_size != 16)
+ goto error;
+ memcpy (&locator->generation_uid, tag_data, 16);
+ break;
+ case 0x4101:
+ if (type != MXF_METADATA_TEXT_LOCATOR
+ && type != MXF_METADATA_NETWORK_LOCATOR)
+ goto DFLT;
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ locator->location = mxf_utf16_to_utf8 (tag_data, tag_size);
+ break;
+ DFLT:
+ default:
+ GST_WRITE_UINT16_BE (data, 0x0000);
+ if (!gst_metadata_add_custom_tag (primer, tag, tag_data, tag_size,
+ &locator->other_tags))
+ goto error;
+ break;
+ }
+
+ next:
+ data += 4 + tag_size;
+ size -= 4 + tag_size;
+ }
+
+ GST_DEBUG ("Parsed locator:");
+ GST_DEBUG (" instance uid = %s", mxf_ul_to_string (&locator->instance_uid,
+ str));
+ GST_DEBUG (" generation uid = %s",
+ mxf_ul_to_string (&locator->generation_uid, str));
+ GST_DEBUG (" location = %s", GST_STR_NULL (locator->location));
+
+ return TRUE;
+
+error:
+ GST_ERROR ("Invalid locator");
+ mxf_metadata_locator_reset (locator);
+
+ return FALSE;
+}
+
+void
+mxf_metadata_locator_reset (MXFMetadataLocator * locator)
+{
+ g_return_if_fail (locator != NULL);
+
+ if (locator->location)
+ g_free (locator->location);
+
+ if (locator->other_tags)
+ g_hash_table_destroy (locator->other_tags);
+
+ memset (locator, 0, sizeof (MXFMetadataLocator));
+}
diff --git a/gst/mxf/mxfparse.h b/gst/mxf/mxfparse.h
new file mode 100644
index 00000000..5b4acd3e
--- /dev/null
+++ b/gst/mxf/mxfparse.h
@@ -0,0 +1,129 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MXF_PARSE_H__
+#define __MXF_PARSE_H__
+
+#include "mxftypes.h"
+
+typedef GstFlowReturn (*MXFEssenceElementHandler) (const MXFUL *key, GstBuffer *buffer, GstCaps *caps, MXFMetadataGenericPackage *package, MXFMetadataTrack *track, MXFMetadataStructuralComponent *component, gpointer mapping_data, GstBuffer **outbuf);
+
+gchar * mxf_ul_to_string (const MXFUL *ul, gchar str[48]);
+gboolean mxf_ul_is_equal (const MXFUL *a, const MXFUL *b);
+gboolean mxf_ul_is_zero (const MXFUL *ul);
+
+gchar *mxf_umid_to_string (const MXFUMID * umid, gchar str[96]);
+gboolean mxf_umid_is_equal (const MXFUMID *a, const MXFUMID *b);
+gboolean mxf_umid_is_zero (const MXFUMID *umid);
+
+gboolean mxf_is_mxf_packet (const MXFUL *key);
+
+gboolean mxf_is_partition_pack (const MXFUL *key);
+gboolean mxf_is_header_partition_pack (const MXFUL *key);
+gboolean mxf_is_body_partition_pack (const MXFUL *key);
+gboolean mxf_is_footer_partition_pack (const MXFUL *key);
+
+gboolean mxf_is_primer_pack (const MXFUL *key);
+
+gboolean mxf_is_metadata (const MXFUL *key);
+
+gboolean mxf_is_random_index_pack (const MXFUL *key);
+gboolean mxf_is_index_table_segment (const MXFUL *key);
+
+gboolean mxf_is_generic_container_system_item (const MXFUL *key);
+gboolean mxf_is_generic_container_essence_element (const MXFUL *key);
+
+gboolean mxf_is_generic_container_essence_container_label (const MXFUL *key);
+
+gboolean mxf_is_fill (const MXFUL *key);
+
+gchar * mxf_utf16_to_utf8 (const guint8 * data, guint16 size);
+
+gboolean mxf_product_version_parse (MXFProductVersion * product_version,
+ const guint8 * data, gsize size);
+
+gboolean mxf_fraction_parse (MXFFraction *fraction, const guint8 *data, guint16 size);
+
+gboolean mxf_timestamp_parse (MXFTimestamp * timestamp, const guint8 * data, gsize size);
+gboolean mxf_timestamp_is_unknown (const MXFTimestamp *a);
+gint mxf_timestamp_compare (const MXFTimestamp *a, const MXFTimestamp *b);
+
+gboolean mxf_partition_pack_parse (const MXFUL *key, MXFPartitionPack *pack, const guint8 *data, gsize size);
+void mxf_partition_pack_reset (MXFPartitionPack *pack);
+
+gboolean mxf_primer_pack_parse (const MXFUL *key, MXFPrimerPack *pack, const guint8 *data, gsize size);
+void mxf_primer_pack_reset (MXFPrimerPack *pack);
+
+gboolean mxf_local_tag_parse (const guint8 * data, gsize size, guint16 * tag,
+ guint16 * tag_size, const guint8 ** tag_data);
+void gst_mxf_local_tag_free (MXFLocalTag *tag);
+
+gboolean gst_metadata_add_custom_tag (const MXFPrimerPack *primer,
+ guint16 tag, const guint8 *tag_data, guint16 tag_size,
+ GHashTable **hash_table);
+
+gboolean mxf_metadata_preface_parse (const MXFUL *key, MXFMetadataPreface *preface, const MXFPrimerPack *primer, const guint8 *data, gsize size);
+void mxf_metadata_preface_reset (MXFMetadataPreface *preface);
+
+gboolean mxf_metadata_identification_parse (const MXFUL *key, MXFMetadataIdentification *identification, const MXFPrimerPack *primer, const guint8 *data, gsize size);
+void mxf_metadata_identification_reset (MXFMetadataIdentification *identification);
+
+gboolean mxf_metadata_content_storage_parse (const MXFUL *key, MXFMetadataContentStorage *content_storage, const MXFPrimerPack *primer, const guint8 *data, gsize size);
+void mxf_metadata_content_storage_reset (MXFMetadataContentStorage *content_storage);
+
+gboolean mxf_metadata_essence_container_data_parse (const MXFUL *key, MXFMetadataEssenceContainerData *essence_container_data, const MXFPrimerPack *primer, const guint8 *data, gsize size);
+void mxf_metadata_essence_container_data_reset (MXFMetadataEssenceContainerData *essence_container_data);
+
+gboolean mxf_metadata_generic_package_parse (const MXFUL *key, MXFMetadataGenericPackage *generic_package, const MXFPrimerPack *primer, const guint8 *data, gsize size);
+void mxf_metadata_generic_package_reset (MXFMetadataGenericPackage *generic_package);
+
+gboolean mxf_metadata_track_parse (const MXFUL *key, MXFMetadataTrack *track, const MXFPrimerPack *primer, const guint8 *data, gsize size);
+void mxf_metadata_track_reset (MXFMetadataTrack *track);
+
+MXFMetadataTrackType mxf_metadata_track_identifier_parse (const MXFUL *track_identifier);
+
+gboolean mxf_metadata_sequence_parse (const MXFUL *key, MXFMetadataSequence *sequence, const MXFPrimerPack *primer, const guint8 *data, gsize size);
+void mxf_metadata_sequence_reset (MXFMetadataSequence *sequence);
+
+gboolean mxf_metadata_structural_component_parse (const MXFUL *key, MXFMetadataStructuralComponent *component, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_structural_component_reset (MXFMetadataStructuralComponent *component);
+
+gboolean mxf_metadata_generic_descriptor_parse (const MXFUL *key, MXFMetadataGenericDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_generic_descriptor_reset (MXFMetadataGenericDescriptor *descriptor);
+
+gboolean mxf_metadata_file_descriptor_parse (const MXFUL *key, MXFMetadataFileDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_file_descriptor_reset (MXFMetadataFileDescriptor *descriptor);
+
+gboolean mxf_metadata_generic_sound_essence_descriptor_parse (const MXFUL *key, MXFMetadataGenericSoundEssenceDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_generic_sound_essence_descriptor_reset (MXFMetadataGenericSoundEssenceDescriptor *descriptor);
+
+gboolean mxf_metadata_generic_picture_essence_descriptor_parse (const MXFUL *key, MXFMetadataGenericPictureEssenceDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_generic_picture_essence_descriptor_reset (MXFMetadataGenericPictureEssenceDescriptor *descriptor);
+
+gboolean mxf_metadata_cdci_picture_essence_descriptor_parse (const MXFUL *key, MXFMetadataCDCIPictureEssenceDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_cdci_picture_essence_descriptor_reset (MXFMetadataCDCIPictureEssenceDescriptor *descriptor);
+
+gboolean mxf_metadata_multiple_descriptor_parse (const MXFUL *key, MXFMetadataMultipleDescriptor *descriptor, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_multiple_descriptor_reset (MXFMetadataMultipleDescriptor *descriptor);
+
+gboolean mxf_metadata_locator_parse (const MXFUL *key, MXFMetadataLocator *locator, const MXFPrimerPack *primer, guint16 type, const guint8 *data, gsize size);
+void mxf_metadata_locator_reset (MXFMetadataLocator *locator);
+
+#endif /* __MXF_PARSE_H__ */
+
diff --git a/gst/mxf/mxftypes.h b/gst/mxf/mxftypes.h
new file mode 100644
index 00000000..c253f2c7
--- /dev/null
+++ b/gst/mxf/mxftypes.h
@@ -0,0 +1,463 @@
+/* GStreamer
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MXF_TYPES_H__
+#define __MXF_TYPES_H__
+
+/* SMPTE 377M 3.2 */
+typedef struct {
+ guint8 u[16];
+} MXFUL;
+
+/* SMPTE 377M 3.2 */
+typedef struct {
+ guint8 u[32];
+} MXFUMID;
+
+/* SMPTE 377M 3.3 */
+typedef struct {
+ gint16 year;
+ guint8 month;
+ guint8 day;
+ guint8 hour;
+ guint8 minute;
+ guint8 second;
+ guint8 quarter_msecond;
+} MXFTimestamp;
+
+/* SMPTE 377M 3.3 */
+typedef struct {
+ guint16 major;
+ guint16 minor;
+ guint16 patch;
+ guint16 build;
+ guint16 release;
+} MXFProductVersion;
+
+/* SMPTE 377M 3.3 */
+typedef struct {
+ gint32 n;
+ gint32 d;
+} MXFFraction;
+
+/* SMPTE 377M 8.3 */
+typedef struct {
+ MXFUL key;
+ guint16 size;
+ guint8 *data;
+} MXFLocalTag;
+
+typedef enum {
+ MXF_PARTITION_PACK_HEADER,
+ MXF_PARTITION_PACK_BODY,
+ MXF_PARTITION_PACK_FOOTER
+} MXFPartitionPackType;
+
+/* SMPTE 377M 6.1, Table 1 and 2 */
+typedef struct {
+ gboolean valid;
+
+ MXFPartitionPackType type;
+
+ gboolean closed;
+ gboolean complete;
+
+ guint16 major_version;
+ guint16 minor_version;
+
+ guint32 kag_size;
+
+ guint64 this_partition;
+ guint64 prev_partition;
+ guint64 footer_partition;
+
+ guint64 header_byte_count;
+ guint64 index_byte_count;
+
+ guint32 index_sid;
+
+ guint64 body_offset;
+
+ guint32 body_sid;
+
+ MXFUL operational_pattern;
+
+ guint32 n_essence_containers;
+ MXFUL *essence_containers;
+} MXFPartitionPack;
+
+/* SMPTE 377M 8.1 */
+typedef struct {
+ gboolean valid;
+
+ GHashTable *mappings;
+} MXFPrimerPack;
+
+/* SMPTE 377M 8.6 table 14 */
+#define MXF_METADATA_PREFACE (0x012f)
+#define MXF_METADATA_IDENTIFICATION (0x0130)
+#define MXF_METADATA_CONTENT_STORAGE (0x0118)
+#define MXF_METADATA_ESSENCE_CONTAINER_DATA (0x0123)
+#define MXF_METADATA_MATERIAL_PACKAGE (0x0136)
+#define MXF_METADATA_SOURCE_PACKAGE (0x0137)
+#define MXF_METADATA_TRACK (0x013b)
+#define MXF_METADATA_EVENT_TRACK (0x0139)
+#define MXF_METADATA_STATIC_TRACK (0x013a)
+#define MXF_METADATA_SEQUENCE (0x010f)
+#define MXF_METADATA_SOURCE_CLIP (0x0111)
+#define MXF_METADATA_TIMECODE_COMPONENT (0x0114)
+#define MXF_METADATA_DM_SEGMENT (0x0141)
+#define MXF_METADATA_DM_SOURCE_CLIP (0x0145)
+#define MXF_METADATA_FILE_DESCRIPTOR (0x0125)
+#define MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (0x0127)
+#define MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR (0x0128)
+#define MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR (0x0129)
+#define MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (0x0142)
+#define MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (0x0143)
+#define MXF_METADATA_MULTIPLE_DESCRIPTOR (0x0144)
+#define MXF_METADATA_NETWORK_LOCATOR (0x0132)
+#define MXF_METADATA_TEXT_LOCATOR (0x0133)
+
+/* SMPTE 377M Annex A, B, C, D */
+typedef struct _MXFMetadataPreface MXFMetadataPreface;
+typedef struct _MXFMetadataIdentification MXFMetadataIdentification;
+typedef struct _MXFMetadataContentStorage MXFMetadataContentStorage;
+typedef struct _MXFMetadataEssenceContainerData MXFMetadataEssenceContainerData;
+typedef struct _MXFMetadataGenericPackage MXFMetadataGenericPackage;
+typedef MXFMetadataGenericPackage MXFMetadataMaterialPackage;
+typedef MXFMetadataGenericPackage MXFMetadataSourcePackage;
+typedef struct _MXFMetadataTrack MXFMetadataTrack;
+typedef struct _MXFMetadataSequence MXFMetadataSequence;
+typedef struct _MXFMetadataStructuralComponent MXFMetadataStructuralComponent;
+typedef struct _MXFMetadataGenericDescriptor MXFMetadataGenericDescriptor;
+typedef struct _MXFMetadataFileDescriptor MXFMetadataFileDescriptor;
+typedef struct _MXFMetadataGenericPictureEssenceDescriptor MXFMetadataGenericPictureEssenceDescriptor;
+typedef struct _MXFMetadataCDCIPictureEssenceDescriptor MXFMetadataCDCIPictureEssenceDescriptor;
+typedef struct _MXFMetadataGenericSoundEssenceDescriptor MXFMetadataGenericSoundEssenceDescriptor;
+typedef struct _MXFMetadataMultipleDescriptor MXFMetadataMultipleDescriptor;
+typedef struct _MXFMetadataLocator MXFMetadataLocator;
+
+struct _MXFMetadataPreface {
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ MXFTimestamp last_modified_date;
+ guint16 version;
+
+ guint32 object_model_version;
+
+ MXFUL primary_package_uid;
+ MXFMetadataGenericPackage *primary_package;
+
+ guint32 n_identifications;
+ MXFUL *identifications_uids;
+ MXFMetadataIdentification **identifications;
+
+ MXFUL content_storage_uid;
+ MXFMetadataContentStorage *content_storage;
+
+ MXFUL operational_pattern;
+
+ guint32 n_essence_containers;
+ MXFUL *essence_containers;
+
+ guint32 n_dm_schemes;
+ MXFUL *dm_schemes;
+
+ GHashTable *other_tags;
+};
+
+struct _MXFMetadataIdentification {
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ gchar *company_name;
+
+ gchar *product_name;
+ MXFProductVersion product_version;
+
+ gchar *version_string;
+
+ MXFUL product_uid;
+
+ MXFTimestamp modification_date;
+
+ MXFProductVersion toolkit_version;
+
+ gchar *platform;
+
+ GHashTable *other_tags;
+};
+
+struct _MXFMetadataContentStorage {
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ guint32 n_packages;
+ MXFUL *packages_uids;
+ MXFMetadataGenericPackage **packages;
+
+ guint32 n_essence_container_data;
+ MXFUL *essence_container_data_uids;
+ MXFMetadataEssenceContainerData **essence_container_data;
+
+ GHashTable *other_tags;
+};
+
+struct _MXFMetadataEssenceContainerData {
+ MXFUL instance_uid;
+
+ MXFUMID linked_package_uid;
+ MXFMetadataGenericPackage *linked_package;
+
+ MXFUL generation_uid;
+
+ guint32 index_sid;
+ guint32 body_sid;
+
+ GHashTable *other_tags;
+};
+
+typedef enum {
+ MXF_METADATA_GENERIC_PACKAGE_SOURCE = 0,
+ MXF_METADATA_GENERIC_PACKAGE_MATERIAL = 1,
+ MXF_METADATA_GENERIC_PACKAGE_TOP_LEVEL_SOURCE = 2
+} MXFMetadataGenericPackageType;
+
+struct _MXFMetadataGenericPackage {
+ MXFUL instance_uid;
+ MXFUMID package_uid;
+ MXFUL generation_uid;
+
+ MXFMetadataGenericPackageType type;
+
+ gchar *name;
+ MXFTimestamp package_creation_date;
+ MXFTimestamp package_modified_date;
+
+ guint32 n_tracks;
+ MXFUL *tracks_uids;
+ MXFMetadataTrack **tracks;
+
+ guint n_timecode_tracks;
+ guint n_metadata_tracks;
+ guint n_essence_tracks;
+ guint n_other_tracks;
+
+ /* Only in Source packages */
+ MXFUL descriptors_uid;
+ guint32 n_descriptors;
+ MXFMetadataGenericDescriptor **descriptors;
+
+ GHashTable *other_tags;
+};
+
+typedef enum {
+ MXF_METADATA_TRACK_UNKNOWN = 0x00,
+ MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE = 0x10,
+ MXF_METADATA_TRACK_TIMECODE_12M_ACTIVE = 0x11,
+ MXF_METADATA_TRACK_TIMECODE_309M = 0x12,
+ MXF_METADATA_TRACK_METADATA = 0x20,
+ MXF_METADATA_TRACK_PICTURE_ESSENCE = 0x30,
+ MXF_METADATA_TRACK_SOUND_ESSENCE = 0x31,
+ MXF_METADATA_TRACK_DATA_ESSENCE = 0x32,
+ MXF_METADATA_TRACK_AUXILIARY_DATA = 0x40,
+ MXF_METADATA_TRACK_PARSED_TEXT = 0x41
+} MXFMetadataTrackType;
+
+struct _MXFMetadataTrack {
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ guint32 track_id;
+ guint32 track_number;
+
+ gchar *track_name;
+
+ MXFFraction edit_rate;
+
+ gint64 origin;
+
+ MXFUL sequence_uid;
+ MXFMetadataSequence *sequence;
+
+ MXFMetadataFileDescriptor **descriptor;
+ guint n_descriptor;
+
+ GHashTable *other_tags;
+};
+
+struct _MXFMetadataSequence {
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ MXFUL data_definition;
+
+ gint64 duration;
+
+ guint32 n_structural_components;
+ MXFUL *structural_components_uids;
+ MXFMetadataStructuralComponent **structural_components;
+
+ GHashTable *other_tags;
+};
+
+struct _MXFMetadataStructuralComponent {
+ guint16 type;
+
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ MXFUL data_definition;
+
+ gint64 duration;
+
+ union {
+ struct {
+ gint64 start_timecode;
+ guint16 rounded_timecode_base;
+ gboolean drop_frame;
+ } timecode_component;
+
+ struct {
+ gint64 start_position;
+ MXFUMID source_package_id;
+ MXFMetadataGenericPackage *source_package;
+
+ guint32 source_track_id;
+ } source_clip;
+ };
+
+ GHashTable *other_tags;
+};
+
+struct _MXFMetadataGenericDescriptor {
+ guint16 type;
+
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ guint32 n_locators;
+ MXFUL *locators_uids;
+ MXFMetadataLocator **locators;
+
+ gboolean is_file_descriptor;
+
+ GHashTable *other_tags;
+};
+
+struct _MXFMetadataFileDescriptor {
+ MXFMetadataGenericDescriptor parent;
+
+ guint32 linked_track_id;
+
+ MXFFraction sample_rate;
+ gint64 container_duration;
+ MXFUL essence_container;
+ MXFUL codec;
+};
+
+struct _MXFMetadataGenericPictureEssenceDescriptor {
+ MXFMetadataFileDescriptor parent;
+
+ guint8 signal_standard;
+ guint8 frame_layout;
+
+ guint32 stored_width;
+ guint32 stored_height;
+ gint32 stored_f2_offset;
+ guint32 sampled_width;
+ guint32 sampled_height;
+ gint32 sampled_x_offset;
+ gint32 sampled_y_offset;
+ guint32 display_height;
+ guint32 display_width;
+ gint32 display_x_offset;
+ gint32 display_y_offset;
+ gint32 display_f2_offset;
+ MXFFraction aspect_ratio;
+
+ guint8 active_format_descriptor;
+ gint32 video_line_map[2];
+ guint8 alpha_transparency;
+ MXFUL capture_gamma;
+
+ guint32 image_alignment_offset;
+ guint32 image_start_offset;
+ guint32 image_end_offset;
+
+ guint8 field_dominance;
+
+ MXFUL picture_essence_coding;
+};
+
+struct _MXFMetadataCDCIPictureEssenceDescriptor {
+ MXFMetadataGenericPictureEssenceDescriptor parent;
+
+ guint32 component_depth;
+ guint32 horizontal_subsampling;
+ guint32 vertical_subsampling;
+ guint8 color_siting;
+ gboolean reversed_byte_order;
+ gint16 padding_bits;
+ guint32 alpha_sample_depth;
+ guint32 black_ref_level;
+ guint32 white_ref_level;
+ guint32 color_range;
+};
+
+struct _MXFMetadataGenericSoundEssenceDescriptor {
+ MXFMetadataFileDescriptor parent;
+
+ MXFFraction audio_sampling_rate;
+
+ gboolean locked;
+
+ gint8 audio_ref_level;
+
+ guint8 electro_spatial_formulation;
+
+ guint32 channel_count;
+ guint32 quantization_bits;
+
+ gint8 dial_norm;
+
+ MXFUL sound_essence_compression;
+};
+
+struct _MXFMetadataMultipleDescriptor {
+ MXFMetadataFileDescriptor parent;
+
+ MXFUL *sub_descriptors_uids;
+ guint32 n_sub_descriptors;
+ MXFMetadataGenericDescriptor **sub_descriptors;
+};
+
+struct _MXFMetadataLocator {
+ guint16 type;
+
+ MXFUL instance_uid;
+ MXFUL generation_uid;
+
+ gchar *location;
+
+ GHashTable *other_tags;
+};
+
+#endif /* __MXF_TYPES_H__ */