| /* GStreamer |
| * Copyright (C) 2008-2009 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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <gst/gst.h> |
| #include <string.h> |
| |
| #include "mxftypes.h" |
| #include "mxfmetadata.h" |
| #include "mxfquark.h" |
| |
| GST_DEBUG_CATEGORY_EXTERN (mxf_debug); |
| #define GST_CAT_DEFAULT mxf_debug |
| |
| G_DEFINE_ABSTRACT_TYPE (MXFMetadataBase, mxf_metadata_base, G_TYPE_OBJECT); |
| |
| static void |
| mxf_metadata_base_finalize (GObject * object) |
| { |
| MXFMetadataBase *self = MXF_METADATA_BASE (object); |
| |
| if (self->other_tags) { |
| g_hash_table_destroy (self->other_tags); |
| self->other_tags = NULL; |
| } |
| |
| G_OBJECT_CLASS (mxf_metadata_base_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_base_handle_tag (MXFMetadataBase * self, MXFPrimerPack * primer, |
| guint16 tag, const guint8 * tag_data, guint tag_size) |
| { |
| return (mxf_local_tag_add_to_hash_table (primer, tag, tag_data, tag_size, |
| &self->other_tags)); |
| } |
| |
| static gboolean |
| mxf_metadata_base_resolve_default (MXFMetadataBase * self, |
| GHashTable * metadata) |
| { |
| return TRUE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_base_to_structure_default (MXFMetadataBase * self) |
| { |
| MXFMetadataBaseClass *klass = MXF_METADATA_BASE_GET_CLASS (self); |
| GstStructure *ret; |
| gchar str[48]; |
| |
| g_return_val_if_fail (klass->name_quark != 0, NULL); |
| |
| ret = gst_structure_new_id_empty (klass->name_quark); |
| |
| if (!mxf_uuid_is_zero (&self->instance_uid)) { |
| mxf_uuid_to_string (&self->instance_uid, str); |
| gst_structure_id_set (ret, MXF_QUARK (INSTANCE_UID), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| if (!mxf_uuid_is_zero (&self->generation_uid)) { |
| mxf_uuid_to_string (&self->generation_uid, str); |
| gst_structure_id_set (ret, MXF_QUARK (GENERATION_UID), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| if (self->other_tags) { |
| MXFLocalTag *tag; |
| GValue va = { 0, }; |
| GValue v = { 0, }; |
| GstStructure *s; |
| GstBuffer *buf; |
| GstMapInfo map; |
| GHashTableIter iter; |
| |
| g_hash_table_iter_init (&iter, self->other_tags); |
| g_value_init (&va, GST_TYPE_ARRAY); |
| |
| while (g_hash_table_iter_next (&iter, NULL, (gpointer) & tag)) { |
| g_value_init (&v, GST_TYPE_STRUCTURE); |
| s = gst_structure_new_id_empty (MXF_QUARK (TAG)); |
| |
| mxf_ul_to_string (&tag->ul, str); |
| |
| buf = gst_buffer_new_and_alloc (tag->size); |
| gst_buffer_map (buf, &map, GST_MAP_WRITE); |
| memcpy (map.data, tag->data, tag->size); |
| gst_buffer_unmap (buf, &map); |
| |
| gst_structure_id_set (s, MXF_QUARK (NAME), G_TYPE_STRING, str, |
| MXF_QUARK (DATA), GST_TYPE_BUFFER, buf, NULL); |
| |
| gst_value_set_structure (&v, s); |
| gst_structure_free (s); |
| gst_buffer_unref (buf); |
| gst_value_array_append_value (&va, &v); |
| g_value_unset (&v); |
| } |
| |
| gst_structure_id_set_value (ret, MXF_QUARK (OTHER_TAGS), &va); |
| g_value_unset (&va); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_base_init (MXFMetadataBase * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_base_class_init (MXFMetadataBaseClass * klass) |
| { |
| GObjectClass *object_class = (GObjectClass *) klass; |
| |
| object_class->finalize = mxf_metadata_base_finalize; |
| klass->handle_tag = mxf_metadata_base_handle_tag; |
| klass->resolve = mxf_metadata_base_resolve_default; |
| klass->to_structure = mxf_metadata_base_to_structure_default; |
| } |
| |
| gboolean |
| mxf_metadata_base_parse (MXFMetadataBase * self, MXFPrimerPack * primer, |
| const guint8 * data, guint size) |
| { |
| guint16 tag, tag_size; |
| const guint8 *tag_data; |
| |
| g_return_val_if_fail (MXF_IS_METADATA_BASE (self), FALSE); |
| g_return_val_if_fail (primer != NULL, FALSE); |
| |
| if (size == 0) |
| return FALSE; |
| |
| g_return_val_if_fail (data != NULL, FALSE); |
| |
| while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) { |
| if (tag_size == 0 || tag == 0x0000) |
| goto next; |
| |
| if (!MXF_METADATA_BASE_GET_CLASS (self)->handle_tag (self, primer, tag, |
| tag_data, tag_size)) |
| return FALSE; |
| next: |
| data += 4 + tag_size; |
| size -= 4 + tag_size; |
| } |
| |
| return TRUE; |
| } |
| |
| gboolean |
| mxf_metadata_base_resolve (MXFMetadataBase * self, GHashTable * metadata) |
| { |
| MXFMetadataBaseClass *klass; |
| gboolean ret = TRUE; |
| |
| g_return_val_if_fail (MXF_IS_METADATA_BASE (self), FALSE); |
| g_return_val_if_fail (metadata != NULL, FALSE); |
| |
| if (self->resolved == MXF_METADATA_BASE_RESOLVE_STATE_SUCCESS) |
| return TRUE; |
| else if (self->resolved != MXF_METADATA_BASE_RESOLVE_STATE_NONE) |
| return FALSE; |
| |
| self->resolved = MXF_METADATA_BASE_RESOLVE_STATE_RUNNING; |
| |
| klass = MXF_METADATA_BASE_GET_CLASS (self); |
| |
| if (klass->resolve) |
| ret = klass->resolve (self, metadata); |
| |
| self->resolved = |
| (ret) ? MXF_METADATA_BASE_RESOLVE_STATE_SUCCESS : |
| MXF_METADATA_BASE_RESOLVE_STATE_FAILURE; |
| |
| return ret; |
| } |
| |
| GstStructure * |
| mxf_metadata_base_to_structure (MXFMetadataBase * self) |
| { |
| MXFMetadataBaseClass *klass; |
| |
| g_return_val_if_fail (MXF_IS_METADATA_BASE (self), NULL); |
| |
| g_return_val_if_fail (self->resolved == |
| MXF_METADATA_BASE_RESOLVE_STATE_SUCCESS, NULL); |
| |
| klass = MXF_METADATA_BASE_GET_CLASS (self); |
| |
| if (klass->to_structure) |
| return klass->to_structure (self); |
| |
| return NULL; |
| } |
| |
| GstBuffer * |
| mxf_metadata_base_to_buffer (MXFMetadataBase * self, MXFPrimerPack * primer) |
| { |
| MXFMetadataBaseClass *klass; |
| GstBuffer *ret; |
| GstMapInfo map; |
| GList *tags, *l; |
| guint size = 0, slen; |
| guint8 ber[9]; |
| MXFLocalTag *t, *last; |
| guint8 *data; |
| |
| g_return_val_if_fail (MXF_IS_METADATA_BASE (self), NULL); |
| g_return_val_if_fail (primer != NULL, NULL); |
| |
| klass = MXF_METADATA_BASE_GET_CLASS (self); |
| g_return_val_if_fail (klass->write_tags, NULL); |
| |
| tags = klass->write_tags (self, primer); |
| g_return_val_if_fail (tags != NULL, NULL); |
| |
| /* Add unknown tags */ |
| if (self->other_tags) { |
| MXFLocalTag *tmp; |
| GHashTableIter iter; |
| |
| g_hash_table_iter_init (&iter, self->other_tags); |
| |
| while (g_hash_table_iter_next (&iter, NULL, (gpointer) & t)) { |
| tmp = g_slice_dup (MXFLocalTag, t); |
| if (t->g_slice) { |
| tmp->data = g_slice_alloc (t->size); |
| mxf_primer_pack_add_mapping (primer, 0x0000, &t->ul); |
| memcpy (tmp->data, t->data, t->size); |
| } else { |
| tmp->data = g_memdup (t->data, t->size); |
| } |
| tags = g_list_prepend (tags, tmp); |
| } |
| } |
| |
| l = g_list_last (tags); |
| last = l->data; |
| tags = g_list_delete_link (tags, l); |
| /* Last element contains the metadata UL */ |
| g_return_val_if_fail (last->size == 0, NULL); |
| |
| for (l = tags; l; l = l->next) { |
| t = l->data; |
| g_assert (G_MAXUINT - t->size >= size); |
| size += 4 + t->size; |
| } |
| |
| slen = mxf_ber_encode_size (size, ber); |
| size += 16 + slen; |
| |
| ret = gst_buffer_new_and_alloc (size); |
| gst_buffer_map (ret, &map, GST_MAP_WRITE); |
| |
| memcpy (map.data, &last->ul, 16); |
| mxf_local_tag_free (last); |
| last = NULL; |
| memcpy (map.data + 16, ber, slen); |
| |
| data = map.data + 16 + slen; |
| size -= 16 + slen; |
| |
| for (l = tags; l; l = l->next) { |
| guint16 local_tag; |
| |
| g_assert (size >= 4); |
| t = l->data; |
| |
| local_tag = |
| GPOINTER_TO_UINT (g_hash_table_lookup (primer->reverse_mappings, |
| &t->ul)); |
| g_assert (local_tag != 0); |
| |
| GST_WRITE_UINT16_BE (data, local_tag); |
| GST_WRITE_UINT16_BE (data + 2, t->size); |
| data += 4; |
| size -= 4; |
| g_assert (size >= t->size); |
| |
| memcpy (data, t->data, t->size); |
| data += t->size; |
| size -= t->size; |
| |
| mxf_local_tag_free (t); |
| } |
| |
| g_list_free (tags); |
| |
| gst_buffer_unmap (ret, &map); |
| |
| return ret; |
| } |
| |
| G_DEFINE_ABSTRACT_TYPE (MXFMetadata, mxf_metadata, MXF_TYPE_METADATA_BASE); |
| |
| static gboolean |
| mxf_metadata_handle_tag (MXFMetadataBase * metadata, MXFPrimerPack * primer, |
| guint16 tag, const guint8 * tag_data, guint tag_size) |
| { |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| MXFMetadata *self = MXF_METADATA (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x3c0a: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->parent.instance_uid, tag_data, 16); |
| GST_DEBUG (" instance uid = %s", |
| mxf_uuid_to_string (&self->parent.instance_uid, str)); |
| break; |
| case 0x0102: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->parent.generation_uid, tag_data, 16); |
| GST_DEBUG (" generation uid = %s", |
| mxf_uuid_to_string (&self->parent.generation_uid, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid metadata local tag 0x%04x of size %u", tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static GList * |
| mxf_metadata_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer) |
| { |
| MXFMetadata *self = MXF_METADATA (m); |
| GList *ret = NULL; |
| MXFLocalTag *t; |
| MXFMetadataClass *klass; |
| |
| g_return_val_if_fail (MXF_IS_METADATA (self), NULL); |
| klass = MXF_METADATA_GET_CLASS (self); |
| |
| /* Last element contains the metadata key */ |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (METADATA), 16); |
| GST_WRITE_UINT16_BE (&t->ul.u[13], klass->type); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (INSTANCE_UID), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (16); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->parent.instance_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3c0a, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (!mxf_uuid_is_zero (&self->parent.generation_uid)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (GENERATION_UID), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (16); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->parent.generation_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x0102, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_class_init (MXFMetadataClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| |
| metadata_base_class->handle_tag = mxf_metadata_handle_tag; |
| metadata_base_class->write_tags = mxf_metadata_write_tags; |
| } |
| |
| static void |
| mxf_metadata_init (MXFMetadata * self) |
| { |
| } |
| |
| static GArray *_mxf_metadata_registry = NULL; |
| |
| #define _add_metadata_type(type) G_STMT_START { \ |
| GType t = type; \ |
| \ |
| g_array_append_val (_mxf_metadata_registry, t); \ |
| } G_STMT_END |
| |
| void |
| mxf_metadata_init_types (void) |
| { |
| g_return_if_fail (_mxf_metadata_registry == NULL); |
| |
| _mxf_metadata_registry = g_array_new (FALSE, TRUE, sizeof (GType)); |
| |
| _add_metadata_type (MXF_TYPE_METADATA_PREFACE); |
| _add_metadata_type (MXF_TYPE_METADATA_IDENTIFICATION); |
| _add_metadata_type (MXF_TYPE_METADATA_CONTENT_STORAGE); |
| _add_metadata_type (MXF_TYPE_METADATA_ESSENCE_CONTAINER_DATA); |
| _add_metadata_type (MXF_TYPE_METADATA_MATERIAL_PACKAGE); |
| _add_metadata_type (MXF_TYPE_METADATA_SOURCE_PACKAGE); |
| _add_metadata_type (MXF_TYPE_METADATA_TIMELINE_TRACK); |
| _add_metadata_type (MXF_TYPE_METADATA_EVENT_TRACK); |
| _add_metadata_type (MXF_TYPE_METADATA_STATIC_TRACK); |
| _add_metadata_type (MXF_TYPE_METADATA_SEQUENCE); |
| _add_metadata_type (MXF_TYPE_METADATA_SOURCE_CLIP); |
| _add_metadata_type (MXF_TYPE_METADATA_FILLER); |
| _add_metadata_type (MXF_TYPE_METADATA_TIMECODE_COMPONENT); |
| _add_metadata_type (MXF_TYPE_METADATA_DM_SEGMENT); |
| _add_metadata_type (MXF_TYPE_METADATA_DM_SOURCE_CLIP); |
| _add_metadata_type (MXF_TYPE_METADATA_FILE_DESCRIPTOR); |
| _add_metadata_type (MXF_TYPE_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR); |
| _add_metadata_type (MXF_TYPE_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR); |
| _add_metadata_type (MXF_TYPE_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR); |
| _add_metadata_type (MXF_TYPE_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR); |
| _add_metadata_type (MXF_TYPE_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR); |
| _add_metadata_type (MXF_TYPE_METADATA_MULTIPLE_DESCRIPTOR); |
| _add_metadata_type (MXF_TYPE_METADATA_NETWORK_LOCATOR); |
| _add_metadata_type (MXF_TYPE_METADATA_TEXT_LOCATOR); |
| } |
| |
| #undef _add_metadata_type |
| |
| void |
| mxf_metadata_register (GType type) |
| { |
| g_return_if_fail (g_type_is_a (type, MXF_TYPE_METADATA)); |
| |
| g_array_append_val (_mxf_metadata_registry, type); |
| } |
| |
| MXFMetadata * |
| mxf_metadata_new (guint16 type, MXFPrimerPack * primer, guint64 offset, |
| const guint8 * data, guint size) |
| { |
| guint i; |
| GType t = G_TYPE_INVALID; |
| MXFMetadata *ret = NULL; |
| |
| g_return_val_if_fail (type != 0, NULL); |
| g_return_val_if_fail (primer != NULL, NULL); |
| g_return_val_if_fail (_mxf_metadata_registry != NULL, NULL); |
| |
| for (i = 0; i < _mxf_metadata_registry->len; i++) { |
| GType tmp = g_array_index (_mxf_metadata_registry, GType, i); |
| MXFMetadataClass *klass = MXF_METADATA_CLASS (g_type_class_ref (tmp)); |
| |
| if (klass->type == type) { |
| g_type_class_unref (klass); |
| t = tmp; |
| break; |
| } |
| g_type_class_unref (klass); |
| } |
| |
| if (t == G_TYPE_INVALID) { |
| GST_WARNING |
| ("No handler for type 0x%04x found -- using generic metadata parser", |
| type); |
| return NULL; |
| } |
| |
| |
| GST_DEBUG ("Metadata type 0x%04x is handled by type %s", type, |
| g_type_name (t)); |
| |
| ret = (MXFMetadata *) g_type_create_instance (t); |
| if (!mxf_metadata_base_parse (MXF_METADATA_BASE (ret), primer, data, size)) { |
| GST_ERROR ("Parsing metadata failed"); |
| g_object_unref (ret); |
| return NULL; |
| } |
| |
| ret->parent.offset = offset; |
| return ret; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataPreface, mxf_metadata_preface, MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_preface_finalize (GObject * object) |
| { |
| MXFMetadataPreface *self = MXF_METADATA_PREFACE (object); |
| |
| g_free (self->identifications_uids); |
| self->identifications_uids = NULL; |
| |
| g_free (self->identifications); |
| self->identifications = NULL; |
| |
| g_free (self->essence_containers); |
| self->essence_containers = NULL; |
| |
| g_free (self->dm_schemes); |
| self->dm_schemes = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_preface_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_preface_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataPreface *self = MXF_METADATA_PREFACE (metadata); |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x3b02: |
| if (!mxf_timestamp_parse (&self->last_modified_date, tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" last modified date = %s", |
| mxf_timestamp_to_string (&self->last_modified_date, str)); |
| break; |
| case 0x3b05: |
| if (tag_size != 2) |
| goto error; |
| self->version = GST_READ_UINT16_BE (tag_data); |
| GST_DEBUG (" version = %u.%u", (self->version >> 8), |
| (self->version & 0x0f)); |
| break; |
| case 0x3b07: |
| if (tag_size != 4) |
| goto error; |
| self->object_model_version = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" object model version = %u", self->object_model_version); |
| break; |
| case 0x3b08: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->primary_package_uid, tag_data, 16); |
| GST_DEBUG (" primary package = %s", |
| mxf_uuid_to_string (&self->primary_package_uid, str)); |
| break; |
| case 0x3b06: |
| if (!mxf_uuid_array_parse (&self->identifications_uids, |
| &self->n_identifications, tag_data, tag_size)) |
| goto error; |
| |
| GST_DEBUG (" number of identifications = %u", self->n_identifications); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_identifications; i++) { |
| GST_DEBUG (" identification %u = %s", i, |
| mxf_uuid_to_string (&self->identifications_uids[i], str)); |
| } |
| } |
| #endif |
| break; |
| case 0x3b03: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->content_storage_uid, tag_data, 16); |
| GST_DEBUG (" content storage = %s", |
| mxf_uuid_to_string (&self->content_storage_uid, str)); |
| break; |
| case 0x3b09: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->operational_pattern, tag_data, 16); |
| GST_DEBUG (" operational pattern = %s", |
| mxf_ul_to_string (&self->operational_pattern, str)); |
| break; |
| case 0x3b0a: |
| if (!mxf_ul_array_parse (&self->essence_containers, |
| &self->n_essence_containers, tag_data, tag_size)) |
| goto error; |
| |
| GST_DEBUG (" number of essence containers = %u", |
| self->n_essence_containers); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_essence_containers; i++) { |
| GST_DEBUG (" essence container %u = %s", i, |
| mxf_ul_to_string (&self->essence_containers[i], str)); |
| } |
| } |
| #endif |
| break; |
| case 0x3b0b: |
| if (!mxf_ul_array_parse (&self->dm_schemes, &self->n_dm_schemes, tag_data, |
| tag_size)) |
| goto error; |
| GST_DEBUG (" number of DM schemes = %u", self->n_dm_schemes); |
| |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_dm_schemes; i++) { |
| GST_DEBUG (" DM schemes %u = %s", i, |
| mxf_ul_to_string (&self->dm_schemes[i], str)); |
| } |
| } |
| #endif |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_preface_parent_class)->handle_tag (metadata, primer, |
| tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid preface local tag 0x%04x of size %u", tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_preface_resolve (MXFMetadataBase * m, GHashTable * metadata) |
| { |
| MXFMetadataPreface *self = MXF_METADATA_PREFACE (m); |
| MXFMetadataBase *current = NULL; |
| guint i; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| if (!mxf_uuid_is_zero (&self->primary_package_uid)) { |
| current = g_hash_table_lookup (metadata, &self->primary_package_uid); |
| if (!current || !MXF_IS_METADATA_GENERIC_PACKAGE (current)) { |
| GST_ERROR ("Primary package %s not found", |
| mxf_uuid_to_string (&self->primary_package_uid, str)); |
| } else { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->primary_package = MXF_METADATA_GENERIC_PACKAGE (current); |
| } |
| } |
| } |
| current = NULL; |
| |
| current = g_hash_table_lookup (metadata, &self->content_storage_uid); |
| if (!current || !MXF_IS_METADATA_CONTENT_STORAGE (current)) { |
| GST_ERROR ("Content storage %s not found", |
| mxf_uuid_to_string (&self->content_storage_uid, str)); |
| return FALSE; |
| } else { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->content_storage = MXF_METADATA_CONTENT_STORAGE (current); |
| } else { |
| GST_ERROR ("Couldn't resolve content storage %s", |
| mxf_uuid_to_string (&self->content_storage_uid, str)); |
| return FALSE; |
| } |
| } |
| current = NULL; |
| |
| if (self->identifications) |
| memset (self->identifications, 0, |
| sizeof (gpointer) * self->n_identifications); |
| else |
| self->identifications = |
| g_new0 (MXFMetadataIdentification *, self->n_identifications); |
| for (i = 0; i < self->n_identifications; i++) { |
| current = g_hash_table_lookup (metadata, &self->identifications_uids[i]); |
| if (current && MXF_IS_METADATA_IDENTIFICATION (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) |
| self->identifications[i] = MXF_METADATA_IDENTIFICATION (current); |
| } |
| current = NULL; |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS (mxf_metadata_preface_parent_class)->resolve (m, |
| metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_preface_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_preface_parent_class)->to_structure |
| (m); |
| MXFMetadataPreface *self = MXF_METADATA_PREFACE (m); |
| gchar str[48]; |
| guint i; |
| |
| if (!mxf_timestamp_is_unknown (&self->last_modified_date)) { |
| mxf_timestamp_to_string (&self->last_modified_date, str); |
| gst_structure_id_set (ret, MXF_QUARK (LAST_MODIFIED_DATE), G_TYPE_STRING, |
| str, NULL); |
| } |
| |
| if (self->version != 0) |
| gst_structure_id_set (ret, MXF_QUARK (VERSION), G_TYPE_UINT, self->version, |
| NULL); |
| |
| if (self->object_model_version != 0) |
| gst_structure_id_set (ret, MXF_QUARK (OBJECT_MODEL_VERSION), G_TYPE_UINT, |
| self->object_model_version, NULL); |
| |
| if (!mxf_uuid_is_zero (&self->primary_package_uid)) { |
| mxf_uuid_to_string (&self->primary_package_uid, str); |
| gst_structure_id_set (ret, MXF_QUARK (PRIMARY_PACKAGE), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| if (self->n_identifications > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_identifications; i++) { |
| GstStructure *s; |
| |
| if (self->identifications[i] == NULL) |
| continue; |
| |
| g_value_init (&val, GST_TYPE_STRUCTURE); |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE |
| (self->identifications[i])); |
| gst_value_set_structure (&val, s); |
| gst_structure_free (s); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (IDENTIFICATIONS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| if (self->content_storage) { |
| GstStructure *s = |
| mxf_metadata_base_to_structure (MXF_METADATA_BASE |
| (self->content_storage)); |
| gst_structure_id_set (ret, MXF_QUARK (CONTENT_STORAGE), GST_TYPE_STRUCTURE, |
| s, NULL); |
| gst_structure_free (s); |
| } |
| |
| if (!mxf_ul_is_zero (&self->operational_pattern)) { |
| mxf_ul_to_string (&self->operational_pattern, str); |
| gst_structure_id_set (ret, MXF_QUARK (OPERATIONAL_PATTERN), G_TYPE_STRING, |
| str, NULL); |
| } |
| |
| if (self->n_essence_containers > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_essence_containers; i++) { |
| if (mxf_ul_is_zero (&self->essence_containers[i])) |
| continue; |
| |
| g_value_init (&val, G_TYPE_STRING); |
| |
| mxf_ul_to_string (&self->essence_containers[i], str); |
| g_value_set_string (&val, str); |
| |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (ESSENCE_CONTAINERS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| if (self->n_dm_schemes > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_dm_schemes; i++) { |
| if (mxf_ul_is_zero (&self->dm_schemes[i])) |
| continue; |
| |
| g_value_init (&val, G_TYPE_STRING); |
| |
| mxf_ul_to_string (&self->dm_schemes[i], str); |
| g_value_set_string (&val, str); |
| |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (DM_SCHEMES), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_preface_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer) |
| { |
| MXFMetadataPreface *self = MXF_METADATA_PREFACE (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_preface_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| guint i; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (LAST_MODIFIED_DATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (8); |
| t->g_slice = TRUE; |
| mxf_timestamp_write (&self->last_modified_date, t->data); |
| mxf_primer_pack_add_mapping (primer, 0x3b02, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (VERSION), 16); |
| t->size = 2; |
| t->data = g_slice_alloc (2); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT16_BE (t->data, self->version); |
| mxf_primer_pack_add_mapping (primer, 0x3b05, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->object_model_version) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (OBJECT_MODEL_VERSION), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (4); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->object_model_version); |
| mxf_primer_pack_add_mapping (primer, 0x3b07, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_uuid_is_zero (&self->primary_package_uid)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PRIMARY_PACKAGE), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (16); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->primary_package_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3b08, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (IDENTIFICATIONS), 16); |
| t->size = 8 + 16 * self->n_identifications; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| mxf_primer_pack_add_mapping (primer, 0x3b06, &t->ul); |
| GST_WRITE_UINT32_BE (t->data, self->n_identifications); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_identifications; i++) { |
| if (!self->identifications[i]) |
| continue; |
| |
| memcpy (t->data + 8 + 16 * i, |
| &MXF_METADATA_BASE (self->identifications[i])->instance_uid, 16); |
| } |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (CONTENT_STORAGE), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| mxf_primer_pack_add_mapping (primer, 0x3b03, &t->ul); |
| memcpy (t->data, &MXF_METADATA_BASE (self->content_storage)->instance_uid, |
| 16); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (OPERATIONAL_PATTERN), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| mxf_primer_pack_add_mapping (primer, 0x3b09, &t->ul); |
| memcpy (t->data, &self->operational_pattern, 16); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ESSENCE_CONTAINERS), 16); |
| t->size = 8 + 16 * self->n_essence_containers; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| mxf_primer_pack_add_mapping (primer, 0x3b0a, &t->ul); |
| GST_WRITE_UINT32_BE (t->data, self->n_essence_containers); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_essence_containers; i++) { |
| memcpy (t->data + 8 + 16 * i, &self->essence_containers[i], 16); |
| } |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DM_SCHEMES), 16); |
| t->size = 8 + 16 * self->n_dm_schemes; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| mxf_primer_pack_add_mapping (primer, 0x3b0b, &t->ul); |
| GST_WRITE_UINT32_BE (t->data, self->n_dm_schemes); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_dm_schemes; i++) { |
| memcpy (t->data + 8 + 16 * i, &self->dm_schemes[i], 16); |
| } |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_preface_init (MXFMetadataPreface * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_preface_class_init (MXFMetadataPrefaceClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_preface_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_preface_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_preface_resolve; |
| metadata_base_class->to_structure = mxf_metadata_preface_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_preface_write_tags; |
| metadata_base_class->name_quark = MXF_QUARK (PREFACE); |
| metadata_class->type = 0x012f; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataIdentification, mxf_metadata_identification, |
| MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_identification_finalize (GObject * object) |
| { |
| MXFMetadataIdentification *self = MXF_METADATA_IDENTIFICATION (object); |
| |
| g_free (self->company_name); |
| self->company_name = NULL; |
| |
| g_free (self->product_name); |
| self->product_name = NULL; |
| |
| g_free (self->version_string); |
| self->version_string = NULL; |
| |
| g_free (self->platform); |
| self->platform = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_identification_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_identification_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataIdentification *self = MXF_METADATA_IDENTIFICATION (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x3c09: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->this_generation_uid, tag_data, 16); |
| GST_DEBUG (" this generation uid = %s", |
| mxf_uuid_to_string (&self->this_generation_uid, str)); |
| break; |
| case 0x3c01: |
| self->company_name = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" company name = %s", GST_STR_NULL (self->company_name)); |
| break; |
| case 0x3c02: |
| self->product_name = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" product name = %s", GST_STR_NULL (self->product_name)); |
| break; |
| case 0x3c03: |
| if (!mxf_product_version_parse (&self->product_version, |
| tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" product version = %u.%u.%u.%u.%u", |
| self->product_version.major, |
| self->product_version.minor, |
| self->product_version.patch, |
| self->product_version.build, self->product_version.release); |
| break; |
| case 0x3c04: |
| self->version_string = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" version string = %s", GST_STR_NULL (self->version_string)); |
| break; |
| case 0x3c05: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->product_uid, tag_data, 16); |
| GST_DEBUG (" product uid = %s", |
| mxf_uuid_to_string (&self->product_uid, str)); |
| break; |
| case 0x3c06: |
| if (!mxf_timestamp_parse (&self->modification_date, tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" modification date = %s", |
| mxf_timestamp_to_string (&self->modification_date, str)); |
| break; |
| case 0x3c07: |
| if (!mxf_product_version_parse (&self->toolkit_version, |
| tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" toolkit version = %u.%u.%u.%u.%u", |
| self->toolkit_version.major, |
| self->toolkit_version.minor, |
| self->toolkit_version.patch, |
| self->toolkit_version.build, self->toolkit_version.release); |
| break; |
| case 0x3c08: |
| self->platform = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" platform = %s", GST_STR_NULL (self->platform)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_identification_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| GST_ERROR ("Invalid identification local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_identification_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_identification_parent_class)->to_structure (m); |
| MXFMetadataIdentification *self = MXF_METADATA_IDENTIFICATION (m); |
| gchar str[48]; |
| |
| if (!mxf_uuid_is_zero (&self->this_generation_uid)) { |
| mxf_uuid_to_string (&self->this_generation_uid, str); |
| gst_structure_id_set (ret, MXF_QUARK (THIS_GENERATION_UID), G_TYPE_STRING, |
| str, NULL); |
| } |
| |
| if (self->company_name) |
| gst_structure_id_set (ret, MXF_QUARK (COMPANY_NAME), G_TYPE_STRING, |
| self->company_name, NULL); |
| |
| if (self->product_name) |
| gst_structure_id_set (ret, MXF_QUARK (PRODUCT_NAME), G_TYPE_STRING, |
| self->product_name, NULL); |
| |
| if (self->product_version.major || |
| self->product_version.minor || |
| self->product_version.patch || |
| self->product_version.build || self->product_version.release) { |
| g_snprintf (str, 48, "%u.%u.%u.%u.%u", self->product_version.major, |
| self->product_version.minor, |
| self->product_version.patch, |
| self->product_version.build, self->product_version.release); |
| gst_structure_id_set (ret, MXF_QUARK (PRODUCT_VERSION), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| if (self->version_string) |
| gst_structure_id_set (ret, MXF_QUARK (VERSION_STRING), G_TYPE_STRING, |
| self->version_string, NULL); |
| |
| if (!mxf_uuid_is_zero (&self->product_uid)) { |
| mxf_uuid_to_string (&self->product_uid, str); |
| gst_structure_id_set (ret, MXF_QUARK (PRODUCT_UID), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| if (!mxf_timestamp_is_unknown (&self->modification_date)) { |
| mxf_timestamp_to_string (&self->modification_date, str); |
| gst_structure_id_set (ret, MXF_QUARK (MODIFICATION_DATE), G_TYPE_STRING, |
| str, NULL); |
| } |
| |
| if (self->toolkit_version.major || |
| self->toolkit_version.minor || |
| self->toolkit_version.patch || |
| self->toolkit_version.build || self->toolkit_version.release) { |
| g_snprintf (str, 48, "%u.%u.%u.%u.%u", self->toolkit_version.major, |
| self->toolkit_version.minor, |
| self->toolkit_version.patch, |
| self->toolkit_version.build, self->toolkit_version.release); |
| gst_structure_id_set (ret, MXF_QUARK (TOOLKIT_VERSION), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| if (self->platform) |
| gst_structure_id_set (ret, MXF_QUARK (PLATFORM), G_TYPE_STRING, |
| self->platform, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_identification_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataIdentification *self = MXF_METADATA_IDENTIFICATION (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_identification_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->company_name) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (COMPANY_NAME), 16); |
| t->data = mxf_utf8_to_utf16 (self->company_name, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x3c01, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->product_name) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PRODUCT_NAME), 16); |
| t->data = mxf_utf8_to_utf16 (self->product_name, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x3c02, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_product_version_is_valid (&self->product_version)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PRODUCT_VERSION), 16); |
| t->size = 10; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| mxf_product_version_write (&self->product_version, t->data); |
| mxf_primer_pack_add_mapping (primer, 0x3c03, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->version_string) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (VERSION_STRING), 16); |
| t->data = mxf_utf8_to_utf16 (self->version_string, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x3c04, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_uuid_is_zero (&self->product_uid)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PRODUCT_UID), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->product_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3c05, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_timestamp_is_unknown (&self->modification_date)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (MODIFICATION_DATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| mxf_timestamp_write (&self->modification_date, t->data); |
| mxf_primer_pack_add_mapping (primer, 0x3c06, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_product_version_is_valid (&self->toolkit_version)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (TOOLKIT_VERSION), 16); |
| t->size = 10; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| mxf_product_version_write (&self->toolkit_version, t->data); |
| mxf_primer_pack_add_mapping (primer, 0x3c07, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->platform) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PLATFORM), 16); |
| t->data = mxf_utf8_to_utf16 (self->platform, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x3c08, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_uuid_is_zero (&self->this_generation_uid)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (THIS_GENERATION_UID), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->this_generation_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3c09, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_identification_init (MXFMetadataIdentification * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_identification_class_init (MXFMetadataIdentificationClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_identification_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_identification_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (IDENTIFICATION); |
| metadata_base_class->to_structure = mxf_metadata_identification_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_identification_write_tags; |
| metadata_class->type = 0x0130; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataContentStorage, mxf_metadata_content_storage, |
| MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_content_storage_finalize (GObject * object) |
| { |
| MXFMetadataContentStorage *self = MXF_METADATA_CONTENT_STORAGE (object); |
| |
| g_free (self->packages); |
| self->packages = NULL; |
| g_free (self->packages_uids); |
| self->packages_uids = NULL; |
| g_free (self->essence_container_data); |
| self->essence_container_data = NULL; |
| g_free (self->essence_container_data_uids); |
| self->essence_container_data_uids = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_content_storage_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_content_storage_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataContentStorage *self = MXF_METADATA_CONTENT_STORAGE (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x1901: |
| if (!mxf_uuid_array_parse (&self->packages_uids, &self->n_packages, |
| tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" number of packages = %u", self->n_packages); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_packages; i++) { |
| GST_DEBUG (" package %u = %s", i, |
| mxf_uuid_to_string (&self->packages_uids[i], str)); |
| } |
| } |
| #endif |
| break; |
| case 0x1902: |
| if (!mxf_uuid_array_parse (&self->essence_container_data_uids, |
| &self->n_essence_container_data, tag_data, tag_size)) |
| goto error; |
| |
| GST_DEBUG (" number of essence container data = %u", |
| self->n_essence_container_data); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_essence_container_data; i++) { |
| GST_DEBUG (" essence container data %u = %s", i, |
| mxf_uuid_to_string (&self->essence_container_data_uids[i], str)); |
| } |
| } |
| #endif |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_content_storage_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid content storage local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_content_storage_resolve (MXFMetadataBase * m, |
| GHashTable * metadata) |
| { |
| MXFMetadataContentStorage *self = MXF_METADATA_CONTENT_STORAGE (m); |
| MXFMetadataBase *current = NULL; |
| guint i; |
| gboolean have_package = FALSE; |
| gboolean have_ecd = FALSE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| if (self->packages) |
| memset (self->packages, 0, sizeof (gpointer) * self->n_packages); |
| else |
| self->packages = g_new0 (MXFMetadataGenericPackage *, self->n_packages); |
| |
| for (i = 0; i < self->n_packages; i++) { |
| current = g_hash_table_lookup (metadata, &self->packages_uids[i]); |
| if (current && MXF_IS_METADATA_GENERIC_PACKAGE (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->packages[i] = MXF_METADATA_GENERIC_PACKAGE (current); |
| have_package = TRUE; |
| } else { |
| GST_ERROR ("Couldn't resolve package %s", |
| mxf_uuid_to_string (&self->packages_uids[i], str)); |
| } |
| } else { |
| GST_ERROR ("Package %s not found", |
| mxf_uuid_to_string (&self->packages_uids[i], str)); |
| } |
| } |
| |
| if (self->essence_container_data) |
| memset (self->essence_container_data, 0, |
| sizeof (gpointer) * self->n_essence_container_data); |
| else |
| self->essence_container_data = |
| g_new0 (MXFMetadataEssenceContainerData *, |
| self->n_essence_container_data); |
| for (i = 0; i < self->n_essence_container_data; i++) { |
| current = |
| g_hash_table_lookup (metadata, &self->essence_container_data_uids[i]); |
| if (current && MXF_IS_METADATA_ESSENCE_CONTAINER_DATA (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->essence_container_data[i] = |
| MXF_METADATA_ESSENCE_CONTAINER_DATA (current); |
| have_ecd = TRUE; |
| } else { |
| GST_ERROR ("Couldn't resolve essence container data %s", |
| mxf_uuid_to_string (&self->essence_container_data_uids[i], str)); |
| } |
| } else { |
| GST_ERROR ("Essence container data %s not found", |
| mxf_uuid_to_string (&self->essence_container_data_uids[i], str)); |
| } |
| } |
| |
| if (!have_package) { |
| GST_ERROR ("Couldn't resolve any package"); |
| return FALSE; |
| } else if (!have_ecd) { |
| GST_ERROR ("Couldn't resolve any essence container data"); |
| return FALSE; |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_content_storage_parent_class)->resolve (m, metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_content_storage_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_content_storage_parent_class)->to_structure (m); |
| MXFMetadataContentStorage *self = MXF_METADATA_CONTENT_STORAGE (m); |
| guint i; |
| |
| if (self->n_packages > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_packages; i++) { |
| GstStructure *s; |
| |
| if (self->packages[i] == NULL) |
| continue; |
| |
| g_value_init (&val, GST_TYPE_STRUCTURE); |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (self->packages |
| [i])); |
| gst_value_set_structure (&val, s); |
| gst_structure_free (s); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (PACKAGES), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| if (self->n_essence_container_data > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_essence_container_data; i++) { |
| GstStructure *s; |
| |
| if (self->essence_container_data[i] == NULL) |
| continue; |
| |
| g_value_init (&val, GST_TYPE_STRUCTURE); |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE |
| (self->essence_container_data[i])); |
| gst_value_set_structure (&val, s); |
| gst_structure_free (s); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (ESSENCE_CONTAINER_DATA), |
| &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_content_storage_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataContentStorage *self = MXF_METADATA_CONTENT_STORAGE (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_content_storage_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| guint i; |
| |
| if (self->packages) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PACKAGES), 16); |
| t->size = 8 + 16 * self->n_packages; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->n_packages); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_packages; i++) { |
| if (!self->packages[i]) |
| continue; |
| |
| memcpy (t->data + 8 + i * 16, |
| &MXF_METADATA_BASE (self->packages[i])->instance_uid, 16); |
| } |
| |
| mxf_primer_pack_add_mapping (primer, 0x1901, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->essence_container_data) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ESSENCE_CONTAINER_DATA), 16); |
| t->size = 8 + 16 * self->n_essence_container_data; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->n_essence_container_data); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_essence_container_data; i++) { |
| if (!self->essence_container_data[i]) |
| continue; |
| |
| memcpy (t->data + 8 + i * 16, |
| &MXF_METADATA_BASE (self->essence_container_data[i])->instance_uid, |
| 16); |
| } |
| |
| mxf_primer_pack_add_mapping (primer, 0x1902, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_content_storage_init (MXFMetadataContentStorage * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_content_storage_class_init (MXFMetadataContentStorageClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_content_storage_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_content_storage_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_content_storage_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (CONTENT_STORAGE); |
| metadata_base_class->to_structure = mxf_metadata_content_storage_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_content_storage_write_tags; |
| metadata_class->type = 0x0118; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataEssenceContainerData, |
| mxf_metadata_essence_container_data, MXF_TYPE_METADATA); |
| |
| static gboolean |
| mxf_metadata_essence_container_data_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataEssenceContainerData *self = |
| MXF_METADATA_ESSENCE_CONTAINER_DATA (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[96]; |
| #endif |
| |
| switch (tag) { |
| case 0x2701: |
| if (tag_size != 32) |
| goto error; |
| memcpy (&self->linked_package_uid, tag_data, 32); |
| GST_DEBUG (" linked package = %s", |
| mxf_umid_to_string (&self->linked_package_uid, str)); |
| break; |
| case 0x3f06: |
| if (tag_size != 4) |
| goto error; |
| self->index_sid = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" index sid = %u", self->index_sid); |
| break; |
| case 0x3f07: |
| if (tag_size != 4) |
| goto error; |
| self->body_sid = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" body sid = %u", self->body_sid); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_essence_container_data_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid essence container data local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_essence_container_data_resolve (MXFMetadataBase * m, |
| GHashTable * metadata) |
| { |
| MXFMetadataEssenceContainerData *self = |
| MXF_METADATA_ESSENCE_CONTAINER_DATA (m); |
| MXFMetadataBase *current = NULL; |
| GHashTableIter iter; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[96]; |
| #endif |
| |
| g_hash_table_iter_init (&iter, metadata); |
| |
| while (g_hash_table_iter_next (&iter, NULL, (gpointer) & current)) { |
| if (MXF_IS_METADATA_SOURCE_PACKAGE (current)) { |
| MXFMetadataSourcePackage *package = MXF_METADATA_SOURCE_PACKAGE (current); |
| |
| if (mxf_umid_is_equal (&package->parent.package_uid, |
| &self->linked_package_uid)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->linked_package = package; |
| } else { |
| GST_ERROR ("Couldn't resolve linked package %s", |
| mxf_umid_to_string (&self->linked_package_uid, str)); |
| } |
| break; |
| } |
| } |
| } |
| |
| if (!self->linked_package) { |
| GST_ERROR ("Couldn't resolve or find linked package %s", |
| mxf_umid_to_string (&self->linked_package_uid, str)); |
| return FALSE; |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_essence_container_data_parent_class)->resolve (m, metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_essence_container_data_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_essence_container_data_parent_class)->to_structure (m); |
| MXFMetadataEssenceContainerData *self = |
| MXF_METADATA_ESSENCE_CONTAINER_DATA (m); |
| gchar str[96]; |
| |
| if (!mxf_umid_is_zero (&self->linked_package_uid)) { |
| mxf_umid_to_string (&self->linked_package_uid, str); |
| gst_structure_id_set (ret, MXF_QUARK (LINKED_PACKAGE), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| gst_structure_id_set (ret, MXF_QUARK (INDEX_SID), G_TYPE_UINT, |
| self->index_sid, MXF_QUARK (BODY_SID), G_TYPE_UINT, self->body_sid, NULL); |
| |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_essence_container_data_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataEssenceContainerData *self = |
| MXF_METADATA_ESSENCE_CONTAINER_DATA (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_essence_container_data_parent_class)->write_tags (m, |
| primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (LINKED_PACKAGE_UID), 16); |
| t->size = 32; |
| t->data = g_slice_alloc0 (32); |
| t->g_slice = TRUE; |
| if (self->linked_package) |
| memcpy (t->data, &self->linked_package->parent.package_uid, 32); |
| mxf_primer_pack_add_mapping (primer, 0x2701, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (BODY_SID), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (4); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->body_sid); |
| mxf_primer_pack_add_mapping (primer, 0x3f07, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->index_sid) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (INDEX_SID), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (4); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->index_sid); |
| mxf_primer_pack_add_mapping (primer, 0x3f06, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_essence_container_data_init (MXFMetadataEssenceContainerData * |
| self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_essence_container_data_class_init |
| (MXFMetadataEssenceContainerDataClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = |
| mxf_metadata_essence_container_data_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_essence_container_data_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (ESSENCE_CONTAINER_DATA); |
| metadata_base_class->to_structure = |
| mxf_metadata_essence_container_data_to_structure; |
| metadata_base_class->write_tags = |
| mxf_metadata_essence_container_data_write_tags; |
| metadata_class->type = 0x0123; |
| } |
| |
| G_DEFINE_ABSTRACT_TYPE (MXFMetadataGenericPackage, mxf_metadata_generic_package, |
| MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_generic_package_finalize (GObject * object) |
| { |
| MXFMetadataGenericPackage *self = MXF_METADATA_GENERIC_PACKAGE (object); |
| |
| g_free (self->name); |
| self->name = NULL; |
| g_free (self->tracks_uids); |
| self->tracks_uids = NULL; |
| |
| g_free (self->tracks); |
| self->tracks = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_generic_package_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_generic_package_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataGenericPackage *self = MXF_METADATA_GENERIC_PACKAGE (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[96]; |
| #endif |
| |
| switch (tag) { |
| case 0x4401: |
| if (tag_size != 32) |
| goto error; |
| memcpy (&self->package_uid, tag_data, 32); |
| GST_DEBUG (" UMID = %s", mxf_umid_to_string (&self->package_uid, str)); |
| break; |
| case 0x4402: |
| self->name = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" name = %s", GST_STR_NULL (self->name)); |
| break; |
| case 0x4405: |
| if (!mxf_timestamp_parse (&self->package_creation_date, |
| tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" creation date = %s", |
| mxf_timestamp_to_string (&self->package_creation_date, str)); |
| break; |
| case 0x4404: |
| if (!mxf_timestamp_parse (&self->package_modified_date, |
| tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" modification date = %s", |
| mxf_timestamp_to_string (&self->package_modified_date, str)); |
| break; |
| case 0x4403: |
| if (!mxf_uuid_array_parse (&self->tracks_uids, &self->n_tracks, tag_data, |
| tag_size)) |
| goto error; |
| |
| GST_DEBUG (" number of tracks = %u", self->n_tracks); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_tracks; i++) { |
| GST_DEBUG (" track %u = %s", i, |
| mxf_uuid_to_string (&self->tracks_uids[i], str)); |
| } |
| } |
| #endif |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_package_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid generic package local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_generic_package_resolve (MXFMetadataBase * m, |
| GHashTable * metadata) |
| { |
| MXFMetadataGenericPackage *self = MXF_METADATA_GENERIC_PACKAGE (m); |
| MXFMetadataBase *current = NULL; |
| guint i; |
| gboolean have_track = FALSE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| if (self->tracks) |
| memset (self->tracks, 0, sizeof (gpointer) * self->n_tracks); |
| else |
| self->tracks = g_new0 (MXFMetadataTrack *, self->n_tracks); |
| for (i = 0; i < self->n_tracks; i++) { |
| current = g_hash_table_lookup (metadata, &self->tracks_uids[i]); |
| if (current && MXF_IS_METADATA_TRACK (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| MXFMetadataTrack *track = MXF_METADATA_TRACK (current); |
| |
| self->tracks[i] = track; |
| have_track = TRUE; |
| if ((track->type & 0xf0) == 0x10) |
| self->n_timecode_tracks++; |
| else if ((track->type & 0xf0) == 0x20) |
| self->n_metadata_tracks++; |
| else if ((track->type & 0xf0) == 0x30) |
| self->n_essence_tracks++; |
| else if ((track->type & 0xf0) == 0x40) |
| self->n_other_tracks++; |
| } else { |
| GST_ERROR ("Track %s couldn't be resolved", |
| mxf_uuid_to_string (&self->tracks_uids[i], str)); |
| } |
| } else { |
| GST_ERROR ("Track %s not found", |
| mxf_uuid_to_string (&self->tracks_uids[i], str)); |
| } |
| } |
| |
| if (!have_track) { |
| GST_ERROR ("Couldn't resolve a track"); |
| return FALSE; |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_package_parent_class)->resolve (m, metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_generic_package_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_package_parent_class)->to_structure (m); |
| MXFMetadataGenericPackage *self = MXF_METADATA_GENERIC_PACKAGE (m); |
| guint i; |
| gchar str[96]; |
| |
| mxf_umid_to_string (&self->package_uid, str); |
| gst_structure_id_set (ret, MXF_QUARK (PACKAGE_UID), G_TYPE_STRING, str, NULL); |
| |
| if (self->name) |
| gst_structure_id_set (ret, MXF_QUARK (NAME), G_TYPE_STRING, self->name, |
| NULL); |
| |
| if (!mxf_timestamp_is_unknown (&self->package_creation_date)) { |
| mxf_timestamp_to_string (&self->package_creation_date, str); |
| gst_structure_id_set (ret, MXF_QUARK (PACKAGE_CREATION_DATE), G_TYPE_STRING, |
| str, NULL); |
| } |
| |
| if (!mxf_timestamp_is_unknown (&self->package_modified_date)) { |
| mxf_timestamp_to_string (&self->package_modified_date, str); |
| gst_structure_id_set (ret, MXF_QUARK (PACKAGE_MODIFIED_DATE), G_TYPE_STRING, |
| str, NULL); |
| } |
| |
| if (self->n_tracks > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_tracks; i++) { |
| GstStructure *s; |
| |
| if (self->tracks[i] == NULL) |
| continue; |
| |
| g_value_init (&val, GST_TYPE_STRUCTURE); |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (self->tracks[i])); |
| gst_value_set_structure (&val, s); |
| gst_structure_free (s); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (TRACKS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_generic_package_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataGenericPackage *self = MXF_METADATA_GENERIC_PACKAGE (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_package_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PACKAGE_UID), 16); |
| t->size = 32; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->package_uid, 32); |
| mxf_primer_pack_add_mapping (primer, 0x4401, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->name) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PACKAGE_NAME), 16); |
| t->data = mxf_utf8_to_utf16 (self->name, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x4402, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PACKAGE_CREATION_DATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| mxf_timestamp_write (&self->package_creation_date, t->data); |
| mxf_primer_pack_add_mapping (primer, 0x4405, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PACKAGE_MODIFIED_DATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| mxf_timestamp_write (&self->package_modified_date, t->data); |
| mxf_primer_pack_add_mapping (primer, 0x4404, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->tracks) { |
| guint i; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (TRACKS), 16); |
| t->size = 8 + 16 * self->n_tracks; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->n_tracks); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_tracks; i++) { |
| if (!self->tracks[i]) |
| continue; |
| |
| memcpy (t->data + 8 + 16 * i, |
| &MXF_METADATA_BASE (self->tracks[i])->instance_uid, 16); |
| } |
| mxf_primer_pack_add_mapping (primer, 0x4403, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_generic_package_init (MXFMetadataGenericPackage * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_generic_package_class_init (MXFMetadataGenericPackageClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| |
| object_class->finalize = mxf_metadata_generic_package_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_generic_package_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_generic_package_resolve; |
| metadata_base_class->to_structure = mxf_metadata_generic_package_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_generic_package_write_tags; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataMaterialPackage, mxf_metadata_material_package, |
| MXF_TYPE_METADATA_GENERIC_PACKAGE); |
| |
| static gboolean |
| mxf_metadata_material_package_resolve (MXFMetadataBase * m, |
| GHashTable * metadata) |
| { |
| gboolean ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_material_package_parent_class)->resolve (m, metadata); |
| MXFMetadataGenericPackage *self = MXF_METADATA_GENERIC_PACKAGE (m); |
| guint i; |
| guint ntracks = 0; |
| |
| if (!ret) |
| return ret; |
| |
| for (i = 0; i < self->n_tracks; i++) { |
| MXFMetadataTrack *track = self->tracks[i]; |
| MXFMetadataSequence *sequence; |
| guint j; |
| |
| if (!track) |
| continue; |
| |
| sequence = track->sequence; |
| |
| if (!sequence || !sequence->structural_components) |
| continue; |
| |
| for (j = 0; j < sequence->n_structural_components; j++) { |
| MXFMetadataSourceClip *sc; |
| MXFMetadataTimelineTrack *st = NULL; |
| guint k; |
| |
| if (!sequence->structural_components[j] |
| || !MXF_IS_METADATA_SOURCE_CLIP (sequence->structural_components[j])) |
| continue; |
| |
| sc = MXF_METADATA_SOURCE_CLIP (sequence->structural_components[j]); |
| |
| if (!sc->source_package) { |
| GST_ERROR ("Material package track %u without resolved source package", |
| i); |
| track = NULL; |
| break; |
| } |
| |
| if (!mxf_metadata_base_resolve (MXF_METADATA_BASE (sc->source_package), |
| metadata)) { |
| GST_ERROR ("Couldn't resolve source package for track %u", i); |
| track = NULL; |
| break; |
| } |
| |
| sc->source_package->top_level = TRUE; |
| for (k = 0; k < sc->source_package->parent.n_tracks; k++) { |
| MXFMetadataTimelineTrack *tmp; |
| |
| if (!sc->source_package->parent.tracks[k] || |
| !MXF_IS_METADATA_TIMELINE_TRACK (sc->source_package->parent. |
| tracks[k])) |
| continue; |
| |
| tmp = |
| MXF_METADATA_TIMELINE_TRACK (sc->source_package->parent.tracks[k]); |
| if (tmp->parent.track_id == sc->source_track_id) { |
| st = tmp; |
| break; |
| } |
| } |
| |
| if (!st) { |
| GST_ERROR ("Material package track %u without resolved source track", |
| i); |
| track = NULL; |
| } |
| } |
| |
| if (track) |
| ntracks++; |
| else |
| self->tracks[i] = NULL; |
| } |
| |
| if (ntracks == 0) { |
| GST_ERROR ("No tracks could be resolved"); |
| return FALSE; |
| } else if (ntracks != self->n_tracks) { |
| GST_WARNING ("Not all tracks could be resolved"); |
| } |
| |
| return TRUE; |
| } |
| |
| static void |
| mxf_metadata_material_package_init (MXFMetadataMaterialPackage * self) |
| { |
| } |
| |
| static void |
| mxf_metadata_material_package_class_init (MXFMetadataMaterialPackageClass * |
| klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->resolve = mxf_metadata_material_package_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (MATERIAL_PACKAGE); |
| metadata_class->type = 0x0136; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataSourcePackage, mxf_metadata_source_package, |
| MXF_TYPE_METADATA_GENERIC_PACKAGE); |
| |
| static gboolean |
| mxf_metadata_source_package_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataSourcePackage *self = MXF_METADATA_SOURCE_PACKAGE (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x4701: |
| if (tag_size != 16) |
| goto error; |
| |
| memcpy (&self->descriptor_uid, tag_data, 16); |
| GST_DEBUG (" descriptor = %s", |
| mxf_uuid_to_string (&self->descriptor_uid, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_package_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid source package local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_source_package_resolve (MXFMetadataBase * m, GHashTable * metadata) |
| { |
| MXFMetadataSourcePackage *self = MXF_METADATA_SOURCE_PACKAGE (m); |
| MXFMetadataGenericPackage *package = MXF_METADATA_GENERIC_PACKAGE (m); |
| MXFMetadataBase *current = NULL; |
| guint i; |
| gboolean ret; |
| MXFMetadataFileDescriptor *d; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| if (mxf_uuid_is_zero (&self->descriptor_uid)) |
| return |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_package_parent_class)->resolve (m, metadata); |
| |
| current = g_hash_table_lookup (metadata, &self->descriptor_uid); |
| if (!current) { |
| GST_ERROR ("Descriptor %s not found", |
| mxf_uuid_to_string (&self->descriptor_uid, str)); |
| return FALSE; |
| } |
| |
| if (!mxf_metadata_base_resolve (MXF_METADATA_BASE (current), metadata)) { |
| GST_ERROR ("Couldn't resolve descriptor %s", |
| mxf_uuid_to_string (&self->descriptor_uid, str)); |
| return FALSE; |
| } |
| |
| self->descriptor = MXF_METADATA_GENERIC_DESCRIPTOR (current); |
| |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_package_parent_class)->resolve (m, metadata); |
| |
| if (!MXF_IS_METADATA_FILE_DESCRIPTOR (self->descriptor)) |
| return ret; |
| |
| d = MXF_METADATA_FILE_DESCRIPTOR (current); |
| |
| for (i = 0; i < package->n_tracks; i++) { |
| if (!package->tracks[i]) |
| continue; |
| |
| if (!MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (d)) { |
| if (d->linked_track_id == package->tracks[i]->track_id || |
| (d->linked_track_id == 0 && package->n_essence_tracks == 1 && |
| (package->tracks[i]->type & 0xf0) == 0x30)) { |
| g_free (package->tracks[i]->descriptor); |
| package->tracks[i]->descriptor = |
| g_new0 (MXFMetadataFileDescriptor *, 1); |
| package->tracks[i]->descriptor[0] = d; |
| package->tracks[i]->n_descriptor = 1; |
| break; |
| } |
| } else { |
| guint n_descriptor = 0, j, k = 0; |
| MXFMetadataMultipleDescriptor *md = MXF_METADATA_MULTIPLE_DESCRIPTOR (d); |
| |
| for (j = 0; j < md->n_sub_descriptors; j++) { |
| MXFMetadataFileDescriptor *fd; |
| |
| if (!md->sub_descriptors[j] || |
| !MXF_METADATA_FILE_DESCRIPTOR (md->sub_descriptors[j])) |
| continue; |
| |
| fd = MXF_METADATA_FILE_DESCRIPTOR (md->sub_descriptors[j]); |
| |
| if (fd->linked_track_id == package->tracks[i]->track_id || |
| (fd->linked_track_id == 0 && package->n_essence_tracks == 1 && |
| (package->tracks[i]->type & 0xf0) == 0x30)) |
| n_descriptor++; |
| } |
| |
| g_free (package->tracks[i]->descriptor); |
| package->tracks[i]->descriptor = |
| g_new0 (MXFMetadataFileDescriptor *, n_descriptor); |
| package->tracks[i]->n_descriptor = n_descriptor; |
| |
| for (j = 0; j < md->n_sub_descriptors; j++) { |
| MXFMetadataFileDescriptor *fd; |
| |
| if (!md->sub_descriptors[j] || |
| !MXF_METADATA_FILE_DESCRIPTOR (md->sub_descriptors[j])) |
| continue; |
| |
| fd = MXF_METADATA_FILE_DESCRIPTOR (md->sub_descriptors[j]); |
| |
| if (fd->linked_track_id == package->tracks[i]->track_id || |
| (fd->linked_track_id == 0 && package->n_essence_tracks == 1 && |
| (package->tracks[i]->type & 0xf0) == 0x30)) { |
| package->tracks[i]->descriptor[k] = fd; |
| k++; |
| } |
| } |
| } |
| } |
| |
| return ret; |
| } |
| |
| static GstStructure * |
| mxf_metadata_source_package_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_package_parent_class)->to_structure (m); |
| MXFMetadataSourcePackage *self = MXF_METADATA_SOURCE_PACKAGE (m); |
| GstStructure *s; |
| |
| if (!self->descriptor) |
| return ret; |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (self->descriptor)); |
| gst_structure_id_set (ret, MXF_QUARK (DESCRIPTOR), GST_TYPE_STRUCTURE, s, |
| NULL); |
| gst_structure_free (s); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_source_package_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataSourcePackage *self = MXF_METADATA_SOURCE_PACKAGE (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_package_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->descriptor) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DESCRIPTOR), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &MXF_METADATA_BASE (self->descriptor)->instance_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x4701, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_source_package_init (MXFMetadataSourcePackage * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_source_package_class_init (MXFMetadataSourcePackageClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = mxf_metadata_source_package_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_source_package_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (SOURCE_PACKAGE); |
| metadata_base_class->to_structure = mxf_metadata_source_package_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_source_package_write_tags; |
| metadata_class->type = 0x0137; |
| } |
| |
| G_DEFINE_ABSTRACT_TYPE (MXFMetadataTrack, mxf_metadata_track, |
| MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_track_finalize (GObject * object) |
| { |
| MXFMetadataTrack *self = MXF_METADATA_TRACK (object); |
| |
| g_free (self->track_name); |
| self->track_name = NULL; |
| g_free (self->descriptor); |
| self->descriptor = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_track_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_track_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataTrack *self = MXF_METADATA_TRACK (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x4801: |
| if (tag_size != 4) |
| goto error; |
| self->track_id = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" track id = %u", self->track_id); |
| break; |
| case 0x4804: |
| if (tag_size != 4) |
| goto error; |
| self->track_number = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" track number = %u", self->track_number); |
| break; |
| case 0x4802: |
| self->track_name = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" track name = %s", GST_STR_NULL (self->track_name)); |
| break; |
| case 0x4803: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->sequence_uid, tag_data, 16); |
| GST_DEBUG (" sequence uid = %s", |
| mxf_uuid_to_string (&self->sequence_uid, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_track_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid track local tag 0x%04x of size %u", tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_track_resolve (MXFMetadataBase * m, GHashTable * metadata) |
| { |
| MXFMetadataTrack *self = MXF_METADATA_TRACK (m); |
| MXFMetadataBase *current = NULL; |
| guint i; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| current = g_hash_table_lookup (metadata, &self->sequence_uid); |
| if (current && MXF_IS_METADATA_SEQUENCE (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->sequence = MXF_METADATA_SEQUENCE (current); |
| } else { |
| GST_ERROR ("Couldn't resolve sequence %s", |
| mxf_uuid_to_string (&self->sequence_uid, str)); |
| return FALSE; |
| } |
| } else { |
| GST_ERROR ("Couldn't find sequence %s", |
| mxf_uuid_to_string (&self->sequence_uid, str)); |
| return FALSE; |
| } |
| |
| self->type = |
| mxf_metadata_track_identifier_parse (&self->sequence->data_definition); |
| if (self->type == MXF_METADATA_TRACK_UNKNOWN) { |
| MXFMetadataSequence *sequence = self->sequence; |
| |
| for (i = 0; i < sequence->n_structural_components; i++) { |
| MXFMetadataStructuralComponent *component = |
| sequence->structural_components[i]; |
| |
| if (!component) |
| continue; |
| |
| self->type = |
| mxf_metadata_track_identifier_parse (&component->data_definition); |
| if (self->type != MXF_METADATA_TRACK_UNKNOWN) |
| break; |
| } |
| } |
| |
| return MXF_METADATA_BASE_CLASS (mxf_metadata_track_parent_class)->resolve (m, |
| metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_track_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_track_parent_class)->to_structure |
| (m); |
| MXFMetadataTrack *self = MXF_METADATA_TRACK (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (TRACK_ID), G_TYPE_UINT, self->track_id, |
| MXF_QUARK (TRACK_NUMBER), G_TYPE_UINT, self->track_number, NULL); |
| |
| if (self->track_name) |
| gst_structure_id_set (ret, MXF_QUARK (TRACK_NAME), G_TYPE_STRING, |
| self->track_name, NULL); |
| |
| if (self->sequence) { |
| GstStructure *s = |
| mxf_metadata_base_to_structure (MXF_METADATA_BASE (self->sequence)); |
| |
| gst_structure_id_set (ret, MXF_QUARK (SEQUENCE), GST_TYPE_STRUCTURE, s, |
| NULL); |
| gst_structure_free (s); |
| } |
| |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_track_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer) |
| { |
| MXFMetadataTrack *self = MXF_METADATA_TRACK (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_track_parent_class)->write_tags (m, |
| primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (TRACK_ID), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->track_id); |
| mxf_primer_pack_add_mapping (primer, 0x4801, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (TRACK_NUMBER), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->track_number); |
| mxf_primer_pack_add_mapping (primer, 0x4804, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->track_name) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (TRACK_NAME), 16); |
| t->data = mxf_utf8_to_utf16 (self->track_name, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x4802, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SEQUENCE), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &MXF_METADATA_BASE (self->sequence)->instance_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x4803, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_track_init (MXFMetadataTrack * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_track_class_init (MXFMetadataTrackClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| |
| object_class->finalize = mxf_metadata_track_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_track_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_track_resolve; |
| metadata_base_class->to_structure = mxf_metadata_track_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_track_write_tags; |
| } |
| |
| /* SMPTE RP224 */ |
| static const struct |
| { |
| const MXFUL *ul; |
| const MXFMetadataTrackType type; |
| } mxf_metadata_track_identifier[] = { |
| { |
| MXF_UL (TRACK_TIMECODE_12M_INACTIVE), |
| MXF_METADATA_TRACK_TIMECODE_12M_INACTIVE}, { |
| MXF_UL (TRACK_TIMECODE_12M_ACTIVE), MXF_METADATA_TRACK_TIMECODE_12M_ACTIVE}, { |
| MXF_UL (TRACK_TIMECODE_309M), MXF_METADATA_TRACK_TIMECODE_309M}, { |
| MXF_UL (TRACK_METADATA), MXF_METADATA_TRACK_METADATA}, { |
| MXF_UL (TRACK_PICTURE_ESSENCE), MXF_METADATA_TRACK_PICTURE_ESSENCE}, { |
| MXF_UL (TRACK_SOUND_ESSENCE), MXF_METADATA_TRACK_SOUND_ESSENCE}, { |
| MXF_UL (TRACK_DATA_ESSENCE), MXF_METADATA_TRACK_DATA_ESSENCE}, { |
| MXF_UL (TRACK_AUXILIARY_DATA), MXF_METADATA_TRACK_AUXILIARY_DATA}, { |
| MXF_UL (TRACK_PARSED_TEXT), MXF_METADATA_TRACK_PARSED_TEXT}, |
| /* Avid video? */ |
| { |
| MXF_UL (TRACK_AVID_PICTURE_ESSENCE), MXF_METADATA_TRACK_PICTURE_ESSENCE} |
| }; |
| |
| 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 (mxf_ul_is_equal (mxf_metadata_track_identifier[i].ul, track_identifier)) |
| return mxf_metadata_track_identifier[i].type; |
| |
| return MXF_METADATA_TRACK_UNKNOWN; |
| } |
| |
| const MXFUL * |
| mxf_metadata_track_identifier_get (MXFMetadataTrackType type) |
| { |
| guint i; |
| |
| for (i = 0; i < G_N_ELEMENTS (mxf_metadata_track_identifier); i++) |
| if (mxf_metadata_track_identifier[i].type == type) |
| return mxf_metadata_track_identifier[i].ul; |
| |
| return NULL; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataTimelineTrack, mxf_metadata_timeline_track, |
| MXF_TYPE_METADATA_TRACK); |
| |
| static gboolean |
| mxf_metadata_timeline_track_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataTimelineTrack *self = MXF_METADATA_TIMELINE_TRACK (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x4b01: |
| if (!mxf_fraction_parse (&self->edit_rate, tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" edit rate = %d/%d", self->edit_rate.n, self->edit_rate.d); |
| break; |
| case 0x4b02: |
| if (tag_size != 8) |
| goto error; |
| self->origin = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" origin = %" G_GINT64_FORMAT, self->origin); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_timeline_track_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid timeline track local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_timeline_track_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_timeline_track_parent_class)->to_structure (m); |
| MXFMetadataTimelineTrack *self = MXF_METADATA_TIMELINE_TRACK (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (EDIT_RATE), GST_TYPE_FRACTION, |
| self->edit_rate.n, self->edit_rate.d, MXF_QUARK (ORIGIN), G_TYPE_INT64, |
| self->origin, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_timeline_track_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataTimelineTrack *self = MXF_METADATA_TIMELINE_TRACK (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_timeline_track_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (EDIT_RATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->edit_rate.n); |
| GST_WRITE_UINT32_BE (t->data + 4, self->edit_rate.d); |
| mxf_primer_pack_add_mapping (primer, 0x4b01, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ORIGIN), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->origin); |
| mxf_primer_pack_add_mapping (primer, 0x4b02, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_timeline_track_init (MXFMetadataTimelineTrack * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_timeline_track_class_init (MXFMetadataTimelineTrackClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = mxf_metadata_timeline_track_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (TIMELINE_TRACK); |
| metadata_base_class->to_structure = mxf_metadata_timeline_track_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_timeline_track_write_tags; |
| metadata_class->type = 0x013b; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataEventTrack, mxf_metadata_event_track, |
| MXF_TYPE_METADATA_TRACK); |
| |
| static gboolean |
| mxf_metadata_event_track_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataEventTrack *self = MXF_METADATA_EVENT_TRACK (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x4901: |
| if (!mxf_fraction_parse (&self->event_edit_rate, tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" event edit rate = %d/%d", self->event_edit_rate.n, |
| self->event_edit_rate.d); |
| break; |
| case 0x4902: |
| if (tag_size != 8) |
| goto error; |
| self->event_origin = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" event origin = %" G_GINT64_FORMAT, self->event_origin); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_event_track_parent_class)->handle_tag (metadata, primer, |
| tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid event track local tag 0x%04x of size %u", tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_event_track_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_event_track_parent_class)->to_structure (m); |
| MXFMetadataEventTrack *self = MXF_METADATA_EVENT_TRACK (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (EVENT_EDIT_RATE), GST_TYPE_FRACTION, |
| self->event_edit_rate.n, self->event_edit_rate.d, |
| MXF_QUARK (EVENT_ORIGIN), G_TYPE_INT64, self->event_origin, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_event_track_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataEventTrack *self = MXF_METADATA_EVENT_TRACK (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_event_track_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (EVENT_EDIT_RATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->event_edit_rate.n); |
| GST_WRITE_UINT32_BE (t->data + 4, self->event_edit_rate.d); |
| mxf_primer_pack_add_mapping (primer, 0x4901, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (EVENT_ORIGIN), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->event_origin); |
| mxf_primer_pack_add_mapping (primer, 0x4902, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_event_track_init (MXFMetadataEventTrack * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_event_track_class_init (MXFMetadataEventTrackClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = mxf_metadata_event_track_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (EVENT_TRACK); |
| metadata_base_class->to_structure = mxf_metadata_event_track_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_event_track_write_tags; |
| metadata_class->type = 0x0139; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataStaticTrack, mxf_metadata_static_track, |
| MXF_TYPE_METADATA_TRACK); |
| |
| static void |
| mxf_metadata_static_track_init (MXFMetadataStaticTrack * self) |
| { |
| } |
| |
| static void |
| mxf_metadata_static_track_class_init (MXFMetadataStaticTrackClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->name_quark = MXF_QUARK (STATIC_TRACK); |
| metadata_class->type = 0x013a; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataSequence, mxf_metadata_sequence, MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_sequence_finalize (GObject * object) |
| { |
| MXFMetadataSequence *self = MXF_METADATA_SEQUENCE (object); |
| |
| g_free (self->structural_components_uids); |
| self->structural_components_uids = NULL; |
| g_free (self->structural_components); |
| self->structural_components = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_sequence_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_sequence_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataSequence *self = MXF_METADATA_SEQUENCE (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x0201: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->data_definition, tag_data, 16); |
| GST_DEBUG (" data definition = %s", |
| mxf_ul_to_string (&self->data_definition, str)); |
| break; |
| case 0x0202: |
| if (tag_size != 8) |
| goto error; |
| self->duration = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" duration = %" G_GINT64_FORMAT, self->duration); |
| break; |
| case 0x1001: |
| if (!mxf_uuid_array_parse (&self->structural_components_uids, |
| &self->n_structural_components, tag_data, tag_size)) |
| goto error; |
| |
| GST_DEBUG (" number of structural components = %u", |
| self->n_structural_components); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_structural_components; i++) { |
| GST_DEBUG (" structural component %u = %s", i, |
| mxf_uuid_to_string (&self->structural_components_uids[i], str)); |
| } |
| } |
| #endif |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_sequence_parent_class)->handle_tag (metadata, primer, |
| tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid sequence local tag 0x%04x of size %u", tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_sequence_resolve (MXFMetadataBase * m, GHashTable * metadata) |
| { |
| MXFMetadataSequence *self = MXF_METADATA_SEQUENCE (m); |
| MXFMetadataBase *current = NULL; |
| guint i; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| if (self->structural_components) |
| memset (self->structural_components, 0, |
| sizeof (gpointer) * self->n_structural_components); |
| else |
| self->structural_components = |
| g_new0 (MXFMetadataStructuralComponent *, |
| self->n_structural_components); |
| for (i = 0; i < self->n_structural_components; i++) { |
| current = |
| g_hash_table_lookup (metadata, &self->structural_components_uids[i]); |
| if (current && MXF_IS_METADATA_STRUCTURAL_COMPONENT (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->structural_components[i] = |
| MXF_METADATA_STRUCTURAL_COMPONENT (current); |
| } else { |
| GST_ERROR ("Couldn't resolve structural component %s", |
| mxf_uuid_to_string (&self->structural_components_uids[i], str)); |
| return FALSE; |
| } |
| } else { |
| GST_ERROR ("Structural component %s not found", |
| mxf_uuid_to_string (&self->structural_components_uids[i], str)); |
| return FALSE; |
| } |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS (mxf_metadata_sequence_parent_class)->resolve (m, |
| metadata); |
| |
| } |
| |
| static GstStructure * |
| mxf_metadata_sequence_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_sequence_parent_class)->to_structure |
| (m); |
| MXFMetadataSequence *self = MXF_METADATA_SEQUENCE (m); |
| guint i; |
| gchar str[48]; |
| |
| mxf_ul_to_string (&self->data_definition, str); |
| gst_structure_id_set (ret, MXF_QUARK (DATA_DEFINITION), G_TYPE_STRING, str, |
| MXF_QUARK (DURATION), G_TYPE_INT64, self->duration, NULL); |
| |
| if (self->n_structural_components > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_structural_components; i++) { |
| GstStructure *s; |
| |
| if (self->structural_components[i] == NULL) |
| continue; |
| |
| g_value_init (&val, GST_TYPE_STRUCTURE); |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE |
| (self->structural_components[i])); |
| gst_value_set_structure (&val, s); |
| gst_structure_free (s); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (STRUCTURAL_COMPONENTS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_sequence_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer) |
| { |
| MXFMetadataSequence *self = MXF_METADATA_SEQUENCE (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_sequence_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DATA_DEFINITION), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->data_definition, 16); |
| mxf_primer_pack_add_mapping (primer, 0x0201, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DURATION), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->duration); |
| mxf_primer_pack_add_mapping (primer, 0x0202, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->structural_components) { |
| guint i; |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (STRUCTURAL_COMPONENTS), 16); |
| t->size = 8 + 16 * self->n_structural_components; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| |
| GST_WRITE_UINT32_BE (t->data, self->n_structural_components); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_structural_components; i++) { |
| if (!self->structural_components[i]) |
| continue; |
| |
| memcpy (t->data + 8 + i * 16, |
| &MXF_METADATA_BASE (self->structural_components[i])->instance_uid, |
| 16); |
| } |
| |
| mxf_primer_pack_add_mapping (primer, 0x1001, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_sequence_init (MXFMetadataSequence * self) |
| { |
| self->duration = -1; |
| } |
| |
| static void |
| mxf_metadata_sequence_class_init (MXFMetadataSequenceClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_sequence_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_sequence_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_sequence_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (SEQUENCE); |
| metadata_base_class->to_structure = mxf_metadata_sequence_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_sequence_write_tags; |
| metadata_class->type = 0x010f; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataStructuralComponent, |
| mxf_metadata_structural_component, MXF_TYPE_METADATA); |
| |
| static gboolean |
| mxf_metadata_structural_component_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataStructuralComponent *self = |
| MXF_METADATA_STRUCTURAL_COMPONENT (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x0201: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->data_definition, tag_data, 16); |
| GST_DEBUG (" data definition = %s", |
| mxf_ul_to_string (&self->data_definition, str)); |
| break; |
| case 0x0202: |
| if (tag_size != 8) |
| goto error; |
| self->duration = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" duration = %" G_GINT64_FORMAT, self->duration); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_structural_component_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid structural component local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_structural_component_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_structural_component_parent_class)->to_structure (m); |
| MXFMetadataStructuralComponent *self = MXF_METADATA_STRUCTURAL_COMPONENT (m); |
| gchar str[48]; |
| |
| mxf_ul_to_string (&self->data_definition, str); |
| gst_structure_id_set (ret, MXF_QUARK (DATA_DEFINITION), G_TYPE_STRING, str, |
| MXF_QUARK (DURATION), G_TYPE_INT64, self->duration, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_structural_component_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataStructuralComponent *self = MXF_METADATA_STRUCTURAL_COMPONENT (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_structural_component_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DATA_DEFINITION), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->data_definition, 16); |
| mxf_primer_pack_add_mapping (primer, 0x0201, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DURATION), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->duration); |
| mxf_primer_pack_add_mapping (primer, 0x0202, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_structural_component_init (MXFMetadataStructuralComponent * self) |
| { |
| self->duration = -1; |
| } |
| |
| static void |
| mxf_metadata_structural_component_class_init |
| (MXFMetadataStructuralComponentClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| |
| metadata_base_class->handle_tag = |
| mxf_metadata_structural_component_handle_tag; |
| metadata_base_class->to_structure = |
| mxf_metadata_structural_component_to_structure; |
| metadata_base_class->write_tags = |
| mxf_metadata_structural_component_write_tags; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataTimecodeComponent, mxf_metadata_timecode_component, |
| MXF_TYPE_METADATA_STRUCTURAL_COMPONENT); |
| |
| static gboolean |
| mxf_metadata_timecode_component_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataTimecodeComponent *self = |
| MXF_METADATA_TIMECODE_COMPONENT (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x1502: |
| if (tag_size != 2) |
| goto error; |
| self->rounded_timecode_base = GST_READ_UINT16_BE (tag_data); |
| GST_DEBUG (" rounded timecode base = %u", self->rounded_timecode_base); |
| break; |
| case 0x1501: |
| if (tag_size != 8) |
| goto error; |
| self->start_timecode = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" start timecode = %" G_GINT64_FORMAT, self->start_timecode); |
| break; |
| case 0x1503: |
| if (tag_size != 1) |
| goto error; |
| self->drop_frame = (GST_READ_UINT8 (tag_data) != 0); |
| GST_DEBUG (" drop frame = %s", (self->drop_frame) ? "yes" : "no"); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_timecode_component_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid timecode component local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_timecode_component_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_timecode_component_parent_class)->to_structure (m); |
| MXFMetadataTimecodeComponent *self = MXF_METADATA_TIMECODE_COMPONENT (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (START_TIMECODE), G_TYPE_INT64, |
| self->start_timecode, MXF_QUARK (ROUNDED_TIMECODE_BASE), G_TYPE_UINT, |
| self->rounded_timecode_base, MXF_QUARK (DROP_FRAME), G_TYPE_BOOLEAN, |
| self->drop_frame, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_timecode_component_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataTimecodeComponent *self = MXF_METADATA_TIMECODE_COMPONENT (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_timecode_component_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ROUNDED_TIMECODE_BASE), 16); |
| t->size = 2; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT16_BE (t->data, self->rounded_timecode_base); |
| mxf_primer_pack_add_mapping (primer, 0x1502, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (START_TIMECODE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->start_timecode); |
| mxf_primer_pack_add_mapping (primer, 0x1501, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DROP_FRAME), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, (self->drop_frame) ? 1 : 0); |
| mxf_primer_pack_add_mapping (primer, 0x1503, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_timecode_component_init (MXFMetadataTimecodeComponent * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_timecode_component_class_init (MXFMetadataTimecodeComponentClass * |
| klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = mxf_metadata_timecode_component_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (TIMECODE_COMPONENT); |
| metadata_base_class->to_structure = |
| mxf_metadata_timecode_component_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_timecode_component_write_tags; |
| metadata_class->type = 0x0114; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataSourceClip, mxf_metadata_source_clip, |
| MXF_TYPE_METADATA_STRUCTURAL_COMPONENT); |
| |
| static gboolean |
| mxf_metadata_source_clip_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataSourceClip *self = MXF_METADATA_SOURCE_CLIP (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[96]; |
| #endif |
| |
| switch (tag) { |
| case 0x1201: |
| if (tag_size != 8) |
| goto error; |
| |
| self->start_position = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" start position = %" G_GINT64_FORMAT, self->start_position); |
| break; |
| case 0x1101: |
| if (tag_size != 32) |
| goto error; |
| |
| memcpy (&self->source_package_id, tag_data, 32); |
| GST_DEBUG (" source package id = %s", |
| mxf_umid_to_string (&self->source_package_id, str)); |
| break; |
| case 0x1102: |
| if (tag_size != 4) |
| goto error; |
| |
| self->source_track_id = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" source track id = %u", self->source_track_id); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_clip_parent_class)->handle_tag (metadata, primer, |
| tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid source clip local tag 0x%04x of size %u", tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_source_clip_resolve (MXFMetadataBase * m, GHashTable * metadata) |
| { |
| MXFMetadataSourceClip *self = MXF_METADATA_SOURCE_CLIP (m); |
| MXFMetadataBase *current = NULL; |
| GHashTableIter iter; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[96]; |
| #endif |
| |
| g_hash_table_iter_init (&iter, metadata); |
| |
| while (g_hash_table_iter_next (&iter, NULL, (gpointer) & current)) { |
| if (MXF_IS_METADATA_SOURCE_PACKAGE (current)) { |
| MXFMetadataGenericPackage *p = MXF_METADATA_GENERIC_PACKAGE (current); |
| |
| if (mxf_umid_is_equal (&p->package_uid, &self->source_package_id)) { |
| self->source_package = MXF_METADATA_SOURCE_PACKAGE (current); |
| break; |
| } |
| } |
| } |
| |
| if (!self->source_package) { |
| GST_ERROR ("Couldn't find source package %s", |
| mxf_umid_to_string (&self->source_package_id, str)); |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS (mxf_metadata_source_clip_parent_class)->resolve |
| (m, metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_source_clip_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_clip_parent_class)->to_structure (m); |
| MXFMetadataSourceClip *self = MXF_METADATA_SOURCE_CLIP (m); |
| gchar str[96]; |
| |
| mxf_umid_to_string (&self->source_package_id, str); |
| gst_structure_id_set (ret, MXF_QUARK (START_POSITION), G_TYPE_INT64, |
| self->start_position, MXF_QUARK (SOURCE_PACKAGE), G_TYPE_STRING, str, |
| MXF_QUARK (SOURCE_TRACK_ID), G_TYPE_UINT, self->source_track_id, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_source_clip_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataSourceClip *self = MXF_METADATA_SOURCE_CLIP (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_source_clip_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (START_POSITION), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->start_position); |
| mxf_primer_pack_add_mapping (primer, 0x1201, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SOURCE_PACKAGE_ID), 16); |
| t->size = 32; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->source_package_id, 32); |
| mxf_primer_pack_add_mapping (primer, 0x1101, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SOURCE_TRACK_ID), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->source_track_id); |
| mxf_primer_pack_add_mapping (primer, 0x1102, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_source_clip_init (MXFMetadataSourceClip * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_source_clip_class_init (MXFMetadataSourceClipClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = mxf_metadata_source_clip_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_source_clip_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (SOURCE_CLIP); |
| metadata_base_class->to_structure = mxf_metadata_source_clip_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_source_clip_write_tags; |
| metadata_class->type = 0x0111; |
| } |
| |
| |
| G_DEFINE_TYPE (MXFMetadataFiller, mxf_metadata_filler, |
| MXF_TYPE_METADATA_STRUCTURAL_COMPONENT); |
| |
| static void |
| mxf_metadata_filler_init (MXFMetadataFiller * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_filler_class_init (MXFMetadataFillerClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->name_quark = MXF_QUARK (FILLER); |
| metadata_class->type = 0x0109; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataDMSourceClip, mxf_metadata_dm_source_clip, |
| MXF_TYPE_METADATA_SOURCE_CLIP); |
| |
| static void |
| mxf_metadata_dm_source_clip_finalize (GObject * object) |
| { |
| MXFMetadataDMSourceClip *self = MXF_METADATA_DM_SOURCE_CLIP (object); |
| |
| g_free (self->track_ids); |
| self->track_ids = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_dm_source_clip_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_dm_source_clip_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataDMSourceClip *self = MXF_METADATA_DM_SOURCE_CLIP (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x6103: |
| { |
| guint32 len; |
| guint i; |
| |
| if (tag_size < 8) |
| goto error; |
| |
| len = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" number of track ids = %u", len); |
| if (len == 0) |
| return TRUE; |
| |
| if (GST_READ_UINT32_BE (tag_data + 4) != 4) |
| goto error; |
| |
| tag_data += 8; |
| tag_size -= 8; |
| |
| if (tag_size / 4 < len) |
| goto error; |
| |
| self->n_track_ids = len; |
| self->track_ids = g_new0 (guint32, len); |
| |
| for (i = 0; i < len; i++) { |
| self->track_ids[i] = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" track id %u = %u", i, self->track_ids[i]); |
| tag_data += 4; |
| tag_size -= 4; |
| } |
| break; |
| } |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_dm_source_clip_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid DM source clip local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_dm_source_clip_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_dm_source_clip_parent_class)->to_structure (m); |
| MXFMetadataDMSourceClip *self = MXF_METADATA_DM_SOURCE_CLIP (m); |
| guint i; |
| |
| if (self->n_track_ids > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_track_ids; i++) { |
| g_value_init (&val, G_TYPE_UINT); |
| |
| g_value_set_uint (&val, self->track_ids[i]); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (TRACK_IDS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_dm_source_clip_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataDMSourceClip *self = MXF_METADATA_DM_SOURCE_CLIP (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_dm_source_clip_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->track_ids) { |
| guint i; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DM_SOURCECLIP_TRACK_IDS), 16); |
| t->size = 8 + 4 * self->n_track_ids; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->n_track_ids); |
| GST_WRITE_UINT32_BE (t->data + 4, 4); |
| for (i = 0; i < self->n_track_ids; i++) |
| GST_WRITE_UINT32_BE (t->data + 8 + i * 4, self->track_ids[i]); |
| mxf_primer_pack_add_mapping (primer, 0x6103, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_dm_source_clip_init (MXFMetadataDMSourceClip * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_dm_source_clip_class_init (MXFMetadataDMSourceClipClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_dm_source_clip_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_dm_source_clip_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (DM_SOURCE_CLIP); |
| metadata_base_class->to_structure = mxf_metadata_dm_source_clip_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_dm_source_clip_write_tags; |
| metadata_class->type = 0x0145; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataDMSegment, mxf_metadata_dm_segment, |
| MXF_TYPE_METADATA_STRUCTURAL_COMPONENT); |
| |
| static void |
| mxf_metadata_dm_segment_finalize (GObject * object) |
| { |
| MXFMetadataDMSegment *self = MXF_METADATA_DM_SEGMENT (object); |
| |
| g_free (self->track_ids); |
| self->track_ids = NULL; |
| |
| g_free (self->event_comment); |
| self->event_comment = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_dm_segment_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_dm_segment_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataDMSegment *self = MXF_METADATA_DM_SEGMENT (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x0601: |
| if (tag_size != 8) |
| goto error; |
| self->event_start_position = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" event start position = %" G_GINT64_FORMAT, |
| self->event_start_position); |
| break; |
| case 0x0602: |
| self->event_comment = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" event comment = %s", GST_STR_NULL (self->event_comment)); |
| break; |
| case 0x6102: |
| { |
| guint32 len; |
| guint i; |
| |
| if (tag_size < 8) |
| goto error; |
| len = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" number of track ids = %u", len); |
| if (len == 0) |
| return TRUE; |
| |
| if (GST_READ_UINT32_BE (tag_data + 4) != 4) |
| goto error; |
| |
| tag_data += 8; |
| tag_size -= 8; |
| |
| if (len < tag_size / 4) |
| goto error; |
| |
| self->n_track_ids = len; |
| self->track_ids = g_new0 (guint32, len); |
| |
| tag_data += 8; |
| tag_size -= 8; |
| |
| for (i = 0; i < len; i++) { |
| self->track_ids[i] = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" track id %u = %u", i, self->track_ids[i]); |
| tag_data += 4; |
| tag_size -= 4; |
| } |
| break; |
| } |
| case 0x6101: |
| if (tag_size != 16) |
| goto error; |
| |
| memcpy (&self->dm_framework_uid, tag_data, 16); |
| GST_DEBUG (" DM framework = %s", |
| mxf_uuid_to_string (&self->dm_framework_uid, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_dm_segment_parent_class)->handle_tag (metadata, primer, |
| tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid DM segment local tag 0x%04x of size %u", tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_dm_segment_resolve (MXFMetadataBase * m, GHashTable * metadata) |
| { |
| MXFMetadataDMSegment *self = MXF_METADATA_DM_SEGMENT (m); |
| MXFMetadataBase *current = NULL; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| current = g_hash_table_lookup (metadata, &self->dm_framework_uid); |
| if (current && MXF_IS_DESCRIPTIVE_METADATA_FRAMEWORK (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->dm_framework = MXF_DESCRIPTIVE_METADATA_FRAMEWORK (current); |
| } else { |
| GST_ERROR ("Couldn't resolve DM framework %s", |
| mxf_uuid_to_string (&self->dm_framework_uid, str)); |
| return FALSE; |
| } |
| } else { |
| GST_ERROR ("Couldn't find DM framework %s", |
| mxf_uuid_to_string (&self->dm_framework_uid, str)); |
| return FALSE; |
| } |
| |
| |
| return |
| MXF_METADATA_BASE_CLASS (mxf_metadata_dm_segment_parent_class)->resolve |
| (m, metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_dm_segment_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_dm_segment_parent_class)->to_structure (m); |
| MXFMetadataDMSegment *self = MXF_METADATA_DM_SEGMENT (m); |
| guint i; |
| |
| gst_structure_id_set (ret, MXF_QUARK (EVENT_START_POSITION), G_TYPE_INT64, |
| self->event_start_position, NULL); |
| |
| if (self->event_comment) |
| gst_structure_id_set (ret, MXF_QUARK (EVENT_COMMENT), G_TYPE_STRING, |
| self->event_comment, NULL); |
| /* FIXME: DMS1 doesn't support serializing to a structure yet */ |
| #if 0 |
| if (self->dm_framework) { |
| GstStructure *s = |
| mxf_metadata_base_to_structure (MXF_METADATA_BASE (self->dm_framework)); |
| |
| gst_structure_id_set (ret, MXF_QUARK (DM_FRAMEWORK), GST_TYPE_STRUCTURE, |
| s, NULL); |
| gst_structure_free (s); |
| } |
| #endif |
| |
| if (self->n_track_ids > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_track_ids; i++) { |
| g_value_init (&val, G_TYPE_UINT); |
| |
| g_value_set_uint (&val, self->track_ids[i]); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (TRACK_IDS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_dm_segment_write_tags (MXFMetadataBase * m, MXFPrimerPack * primer) |
| { |
| MXFMetadataDMSegment *self = MXF_METADATA_DM_SEGMENT (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS (mxf_metadata_dm_segment_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->event_start_position != -1) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (EVENT_START_POSITION), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->event_start_position); |
| mxf_primer_pack_add_mapping (primer, 0x0601, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->event_comment) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (EVENT_COMMENT), 16); |
| t->data = mxf_utf8_to_utf16 (self->event_comment, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x0602, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->track_ids) { |
| guint i; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DM_SEGMENT_TRACK_IDS), 16); |
| t->size = 8 + 4 * self->n_track_ids; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->n_track_ids); |
| GST_WRITE_UINT32_BE (t->data + 4, 4); |
| for (i = 0; i < self->n_track_ids; i++) |
| GST_WRITE_UINT32_BE (t->data + 8 + i * 4, self->track_ids[i]); |
| mxf_primer_pack_add_mapping (primer, 0x6102, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->dm_framework) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DM_FRAMEWORK), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &MXF_METADATA_BASE (self->dm_framework)->instance_uid, 16); |
| mxf_primer_pack_add_mapping (primer, 0x6101, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_dm_segment_init (MXFMetadataDMSegment * self) |
| { |
| self->event_start_position = -1; |
| } |
| |
| static void |
| mxf_metadata_dm_segment_class_init (MXFMetadataDMSegmentClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_dm_segment_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_dm_segment_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_dm_segment_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (DM_SEGMENT); |
| metadata_base_class->to_structure = mxf_metadata_dm_segment_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_dm_segment_write_tags; |
| metadata_class->type = 0x0141; |
| } |
| |
| G_DEFINE_ABSTRACT_TYPE (MXFMetadataGenericDescriptor, |
| mxf_metadata_generic_descriptor, MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_generic_descriptor_finalize (GObject * object) |
| { |
| MXFMetadataGenericDescriptor *self = MXF_METADATA_GENERIC_DESCRIPTOR (object); |
| |
| g_free (self->locators_uids); |
| self->locators_uids = NULL; |
| |
| g_free (self->locators); |
| self->locators = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_generic_descriptor_parent_class)->finalize |
| (object); |
| } |
| |
| static gboolean |
| mxf_metadata_generic_descriptor_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataGenericDescriptor *self = |
| MXF_METADATA_GENERIC_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x2f01: |
| if (!mxf_uuid_array_parse (&self->locators_uids, &self->n_locators, |
| tag_data, tag_size)) |
| goto error; |
| |
| GST_DEBUG (" number of locators = %u", self->n_locators); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_locators; i++) { |
| GST_DEBUG (" locator %u = %s", i, |
| mxf_uuid_to_string (&self->locators_uids[i], str)); |
| } |
| } |
| #endif |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_descriptor_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid generic descriptor local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_generic_descriptor_resolve (MXFMetadataBase * m, |
| GHashTable * metadata) |
| { |
| MXFMetadataGenericDescriptor *self = MXF_METADATA_GENERIC_DESCRIPTOR (m); |
| MXFMetadataBase *current = NULL; |
| guint i; |
| gboolean have_locator = FALSE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| if (self->locators) |
| memset (self->locators, 0, sizeof (gpointer) * self->n_locators); |
| else |
| self->locators = g_new0 (MXFMetadataLocator *, self->n_locators); |
| for (i = 0; i < self->n_locators; i++) { |
| current = g_hash_table_lookup (metadata, &self->locators_uids[i]); |
| if (current && MXF_IS_METADATA_LOCATOR (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->locators[i] = MXF_METADATA_LOCATOR (current); |
| have_locator = TRUE; |
| } else { |
| GST_ERROR ("Couldn't resolve locator %s", |
| mxf_uuid_to_string (&self->locators_uids[i], str)); |
| } |
| } else { |
| GST_ERROR ("Locator %s not found", |
| mxf_uuid_to_string (&self->locators_uids[i], str)); |
| } |
| } |
| |
| if (!have_locator && self->n_locators > 0) { |
| GST_ERROR ("Couldn't resolve a locator"); |
| return FALSE; |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_descriptor_parent_class)->resolve (m, metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_generic_descriptor_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_descriptor_parent_class)->to_structure (m); |
| MXFMetadataGenericDescriptor *self = MXF_METADATA_GENERIC_DESCRIPTOR (m); |
| guint i; |
| |
| if (self->n_locators > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_locators; i++) { |
| GstStructure *s; |
| |
| if (self->locators[i] == NULL) |
| continue; |
| |
| g_value_init (&val, GST_TYPE_STRUCTURE); |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (self->locators |
| [i])); |
| gst_value_set_structure (&val, s); |
| gst_structure_free (s); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (LOCATORS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_generic_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataGenericDescriptor *self = MXF_METADATA_GENERIC_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_descriptor_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->locators) { |
| guint i; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (LOCATORS), 16); |
| t->size = 8 + 16 * self->n_locators; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->n_locators); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_locators; i++) { |
| if (!self->locators[i]) |
| continue; |
| memcpy (t->data + 8 + 16 * i, |
| &MXF_METADATA_BASE (self->locators[i])->instance_uid, 16); |
| } |
| mxf_primer_pack_add_mapping (primer, 0x2f01, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_generic_descriptor_init (MXFMetadataGenericDescriptor * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_generic_descriptor_class_init (MXFMetadataGenericDescriptorClass * |
| klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| |
| object_class->finalize = mxf_metadata_generic_descriptor_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_generic_descriptor_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_generic_descriptor_resolve; |
| metadata_base_class->to_structure = |
| mxf_metadata_generic_descriptor_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_generic_descriptor_write_tags; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataFileDescriptor, mxf_metadata_file_descriptor, |
| MXF_TYPE_METADATA_GENERIC_DESCRIPTOR); |
| |
| static gboolean |
| mxf_metadata_file_descriptor_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataFileDescriptor *self = MXF_METADATA_FILE_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x3006: |
| if (tag_size != 4) |
| goto error; |
| self->linked_track_id = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" linked track id = %u", self->linked_track_id); |
| break; |
| case 0x3001: |
| if (!mxf_fraction_parse (&self->sample_rate, tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" sample rate = %d/%d", self->sample_rate.n, |
| self->sample_rate.d); |
| break; |
| case 0x3002: |
| if (tag_size != 8) |
| goto error; |
| self->container_duration = GST_READ_UINT64_BE (tag_data); |
| GST_DEBUG (" container duration = %" G_GINT64_FORMAT, |
| self->container_duration); |
| break; |
| case 0x3004: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->essence_container, tag_data, 16); |
| GST_DEBUG (" essence container = %s", |
| mxf_ul_to_string (&self->essence_container, str)); |
| break; |
| case 0x3005: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->codec, tag_data, 16); |
| GST_DEBUG (" codec = %s", mxf_ul_to_string (&self->codec, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_file_descriptor_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid file descriptor local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_file_descriptor_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_file_descriptor_parent_class)->to_structure (m); |
| MXFMetadataFileDescriptor *self = MXF_METADATA_FILE_DESCRIPTOR (m); |
| gchar str[48]; |
| |
| if (self->linked_track_id) |
| gst_structure_id_set (ret, MXF_QUARK (LINKED_TRACK_ID), G_TYPE_UINT, |
| self->linked_track_id, NULL); |
| |
| if (self->sample_rate.n && self->sample_rate.d) |
| gst_structure_id_set (ret, MXF_QUARK (SAMPLE_RATE), GST_TYPE_FRACTION, |
| self->sample_rate.n, self->sample_rate.d, NULL); |
| |
| if (self->container_duration) |
| gst_structure_id_set (ret, MXF_QUARK (CONTAINER_DURATION), G_TYPE_INT64, |
| self->container_duration, NULL); |
| |
| mxf_ul_to_string (&self->essence_container, str); |
| gst_structure_id_set (ret, MXF_QUARK (ESSENCE_CONTAINER), G_TYPE_STRING, str, |
| NULL); |
| |
| if (!mxf_ul_is_zero (&self->codec)) { |
| mxf_ul_to_string (&self->codec, str); |
| gst_structure_id_set (ret, MXF_QUARK (CODEC), G_TYPE_STRING, str, NULL); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_file_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataFileDescriptor *self = MXF_METADATA_FILE_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_file_descriptor_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->linked_track_id) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (LINKED_TRACK_ID), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->linked_track_id); |
| mxf_primer_pack_add_mapping (primer, 0x3006, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SAMPLE_RATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->sample_rate.n); |
| GST_WRITE_UINT32_BE (t->data + 4, self->sample_rate.d); |
| mxf_primer_pack_add_mapping (primer, 0x3001, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->container_duration > 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (CONTAINER_DURATION), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT64_BE (t->data, self->container_duration); |
| mxf_primer_pack_add_mapping (primer, 0x3002, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ESSENCE_CONTAINER), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->essence_container, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3004, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (!mxf_ul_is_zero (&self->codec)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (CODEC), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->codec, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3005, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_file_descriptor_init (MXFMetadataFileDescriptor * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_file_descriptor_class_init (MXFMetadataFileDescriptorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = mxf_metadata_file_descriptor_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (FILE_DESCRIPTOR); |
| metadata_base_class->to_structure = mxf_metadata_file_descriptor_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_file_descriptor_write_tags; |
| metadata_class->type = 0x0125; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataGenericPictureEssenceDescriptor, |
| mxf_metadata_generic_picture_essence_descriptor, |
| MXF_TYPE_METADATA_FILE_DESCRIPTOR); |
| |
| static gboolean |
| mxf_metadata_generic_picture_essence_descriptor_handle_tag (MXFMetadataBase * |
| metadata, MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataGenericPictureEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x3215: |
| if (tag_size != 1) |
| goto error; |
| self->signal_standard = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" signal standard = %u", self->signal_standard); |
| break; |
| case 0x320c: |
| if (tag_size != 1) |
| goto error; |
| self->frame_layout = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" frame layout = %u", self->frame_layout); |
| break; |
| case 0x3203: |
| if (tag_size != 4) |
| goto error; |
| self->stored_width = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" stored width = %u", self->stored_width); |
| break; |
| case 0x3202: |
| if (tag_size != 4) |
| goto error; |
| self->stored_height = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" stored height = %u", self->stored_height); |
| break; |
| case 0x3216: |
| if (tag_size != 4) |
| goto error; |
| self->stored_f2_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" stored f2 offset = %d", self->stored_f2_offset); |
| break; |
| case 0x3205: |
| if (tag_size != 4) |
| goto error; |
| self->sampled_width = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" sampled width = %u", self->sampled_width); |
| break; |
| case 0x3204: |
| if (tag_size != 4) |
| goto error; |
| self->sampled_height = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" sampled height = %u", self->sampled_height); |
| break; |
| case 0x3206: |
| if (tag_size != 4) |
| goto error; |
| self->sampled_x_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" sampled x offset = %d", self->sampled_x_offset); |
| break; |
| case 0x3207: |
| if (tag_size != 4) |
| goto error; |
| self->sampled_y_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" sampled y offset = %d", self->sampled_y_offset); |
| break; |
| case 0x3208: |
| if (tag_size != 4) |
| goto error; |
| self->display_height = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" display height = %u", self->display_height); |
| break; |
| case 0x3209: |
| if (tag_size != 4) |
| goto error; |
| self->display_width = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" display width = %u", self->display_width); |
| break; |
| case 0x320a: |
| if (tag_size != 4) |
| goto error; |
| self->display_x_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" display x offset = %d", self->display_x_offset); |
| break; |
| case 0x320b: |
| if (tag_size != 4) |
| goto error; |
| self->display_y_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" display y offset = %d", self->display_y_offset); |
| break; |
| case 0x3217: |
| if (tag_size != 4) |
| goto error; |
| self->display_f2_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" display f2 offset = %d", self->display_f2_offset); |
| break; |
| case 0x320e: |
| if (!mxf_fraction_parse (&self->aspect_ratio, tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" aspect ratio = %d/%d", self->aspect_ratio.n, |
| self->aspect_ratio.d); |
| break; |
| case 0x3218: |
| if (tag_size != 1) |
| goto error; |
| self->active_format_descriptor = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" active format descriptor = %u", |
| self->active_format_descriptor); |
| break; |
| case 0x320d: |
| if (tag_size < 8) |
| goto error; |
| |
| if (GST_READ_UINT32_BE (tag_data) == 0) |
| return TRUE; |
| |
| if (GST_READ_UINT32_BE (tag_data + 4) != 4) |
| goto error; |
| |
| if (GST_READ_UINT32_BE (tag_data) != 1 && |
| GST_READ_UINT32_BE (tag_data) != 2) |
| goto error; |
| |
| if ((GST_READ_UINT32_BE (tag_data) == 1 && tag_size != 12) || |
| (GST_READ_UINT32_BE (tag_data) == 2 && tag_size != 16)) |
| goto error; |
| |
| self->video_line_map[0] = GST_READ_UINT32_BE (tag_data + 8); |
| |
| /* Workaround for files created by ffmpeg */ |
| if (GST_READ_UINT32_BE (tag_data) == 1) |
| self->video_line_map[0] = 0; |
| else |
| self->video_line_map[1] = GST_READ_UINT32_BE (tag_data + 12); |
| |
| GST_DEBUG (" video line map = {%i, %i}", self->video_line_map[0], |
| self->video_line_map[1]); |
| break; |
| case 0x320f: |
| if (tag_size != 1) |
| goto error; |
| self->alpha_transparency = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" alpha transparency = %u", self->alpha_transparency); |
| break; |
| case 0x3210: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->capture_gamma, tag_data, 16); |
| GST_DEBUG (" capture gamma = %s", |
| mxf_ul_to_string (&self->capture_gamma, str)); |
| break; |
| case 0x3211: |
| if (tag_size != 4) |
| goto error; |
| self->image_alignment_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" image alignment offset = %u", self->image_alignment_offset); |
| break; |
| case 0x3213: |
| if (tag_size != 4) |
| goto error; |
| self->image_start_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" image start offset = %u", self->image_start_offset); |
| break; |
| case 0x3214: |
| if (tag_size != 4) |
| goto error; |
| self->image_end_offset = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" image end offset = %u", self->image_end_offset); |
| break; |
| case 0x3212: |
| if (tag_size != 1) |
| goto error; |
| self->field_dominance = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" field dominance = %u", self->field_dominance); |
| break; |
| case 0x3201: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->picture_essence_coding, tag_data, 16); |
| GST_DEBUG (" picture essence coding = %s", |
| mxf_ul_to_string (&self->picture_essence_coding, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_picture_essence_descriptor_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR |
| ("Invalid generic picture essence descriptor local tag 0x%04x of size %u", |
| tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_generic_picture_essence_descriptor_to_structure (MXFMetadataBase * |
| m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_picture_essence_descriptor_parent_class)->to_structure |
| (m); |
| MXFMetadataGenericPictureEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (m); |
| gchar str[48]; |
| |
| gst_structure_id_set (ret, MXF_QUARK (SIGNAL_STANDARD), G_TYPE_UCHAR, |
| self->signal_standard, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (FRAME_LAYOUT), G_TYPE_UCHAR, |
| self->frame_layout, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (STORED_WIDTH), G_TYPE_UINT, |
| self->stored_width, MXF_QUARK (STORED_HEIGHT), G_TYPE_UINT, |
| self->stored_height, NULL); |
| |
| if (self->stored_f2_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (STORED_F2_OFFSET), G_TYPE_INT, |
| self->stored_f2_offset, NULL); |
| |
| if (self->sampled_width != 0 && self->sampled_height != 0) |
| gst_structure_id_set (ret, MXF_QUARK (SAMPLED_WIDTH), G_TYPE_UINT, |
| self->sampled_width, MXF_QUARK (SAMPLED_HEIGHT), G_TYPE_UINT, |
| self->sampled_height, NULL); |
| |
| if (self->sampled_x_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (SAMPLED_X_OFFSET), G_TYPE_INT, |
| self->sampled_x_offset, NULL); |
| |
| if (self->sampled_y_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (SAMPLED_Y_OFFSET), G_TYPE_INT, |
| self->sampled_y_offset, NULL); |
| |
| if (self->display_width != 0 && self->display_height != 0) |
| gst_structure_id_set (ret, MXF_QUARK (DISPLAY_WIDTH), G_TYPE_UINT, |
| self->display_width, MXF_QUARK (DISPLAY_HEIGHT), G_TYPE_UINT, |
| self->display_height, NULL); |
| |
| if (self->display_x_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (DISPLAY_X_OFFSET), G_TYPE_INT, |
| self->display_x_offset, NULL); |
| |
| if (self->display_y_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (DISPLAY_Y_OFFSET), G_TYPE_INT, |
| self->display_y_offset, NULL); |
| |
| if (self->display_f2_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (DISPLAY_F2_OFFSET), G_TYPE_INT, |
| self->display_f2_offset, NULL); |
| |
| if (self->aspect_ratio.n != 0 && self->aspect_ratio.d != 0) |
| gst_structure_id_set (ret, MXF_QUARK (ASPECT_RATIO), GST_TYPE_FRACTION, |
| self->aspect_ratio.n, self->aspect_ratio.d, NULL); |
| |
| if (self->active_format_descriptor) |
| gst_structure_id_set (ret, MXF_QUARK (ACTIVE_FORMAT_DESCRIPTOR), |
| G_TYPE_UCHAR, self->active_format_descriptor, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (VIDEO_LINE_MAP_0), G_TYPE_UINT, |
| self->video_line_map[0], MXF_QUARK (VIDEO_LINE_MAP_1), G_TYPE_UINT, |
| self->video_line_map[1], NULL); |
| |
| if (self->alpha_transparency != 0) |
| gst_structure_id_set (ret, MXF_QUARK (ALPHA_TRANSPARENCY), G_TYPE_UCHAR, |
| self->alpha_transparency, NULL); |
| |
| if (!mxf_ul_is_zero (&self->capture_gamma)) { |
| mxf_ul_to_string (&self->capture_gamma, str); |
| gst_structure_id_set (ret, MXF_QUARK (CAPTURE_GAMMA), G_TYPE_STRING, str, |
| NULL); |
| } |
| |
| if (self->image_alignment_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (IMAGE_ALIGNMENT_OFFSET), G_TYPE_UINT, |
| self->image_alignment_offset, NULL); |
| |
| if (self->image_start_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (IMAGE_START_OFFSET), G_TYPE_UINT, |
| self->image_start_offset, NULL); |
| |
| if (self->image_end_offset != 0) |
| gst_structure_id_set (ret, MXF_QUARK (IMAGE_END_OFFSET), G_TYPE_UINT, |
| self->image_end_offset, NULL); |
| |
| if (self->field_dominance != 0) |
| gst_structure_id_set (ret, MXF_QUARK (FIELD_DOMINANCE), G_TYPE_UCHAR, |
| self->field_dominance, NULL); |
| |
| if (!mxf_ul_is_zero (&self->picture_essence_coding)) { |
| mxf_ul_to_string (&self->picture_essence_coding, str); |
| gst_structure_id_set (ret, MXF_QUARK (PICTURE_ESSENCE_CODING), |
| G_TYPE_STRING, str, NULL); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_generic_picture_essence_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataGenericPictureEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_picture_essence_descriptor_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->signal_standard != 1) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SIGNAL_STANDARD), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->signal_standard); |
| mxf_primer_pack_add_mapping (primer, 0x3215, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (FRAME_LAYOUT), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->frame_layout); |
| mxf_primer_pack_add_mapping (primer, 0x320c, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (STORED_WIDTH), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->stored_width); |
| mxf_primer_pack_add_mapping (primer, 0x3203, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (STORED_HEIGHT), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->stored_height); |
| mxf_primer_pack_add_mapping (primer, 0x3202, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->stored_f2_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (STORED_F2_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->stored_f2_offset); |
| mxf_primer_pack_add_mapping (primer, 0x3216, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->sampled_width != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SAMPLED_WIDTH), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->sampled_width); |
| mxf_primer_pack_add_mapping (primer, 0x3205, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->sampled_height != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SAMPLED_HEIGHT), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->sampled_height); |
| mxf_primer_pack_add_mapping (primer, 0x3204, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->sampled_x_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SAMPLED_X_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->sampled_x_offset); |
| mxf_primer_pack_add_mapping (primer, 0x3206, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->sampled_y_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SAMPLED_Y_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->sampled_y_offset); |
| mxf_primer_pack_add_mapping (primer, 0x3207, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->display_height != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DISPLAY_HEIGHT), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->display_height); |
| mxf_primer_pack_add_mapping (primer, 0x3208, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->display_width != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DISPLAY_WIDTH), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->display_width); |
| mxf_primer_pack_add_mapping (primer, 0x3209, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->display_x_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DISPLAY_X_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->display_x_offset); |
| mxf_primer_pack_add_mapping (primer, 0x320a, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->display_y_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DISPLAY_Y_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->display_y_offset); |
| mxf_primer_pack_add_mapping (primer, 0x320b, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->display_f2_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DISPLAY_F2_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->display_f2_offset); |
| mxf_primer_pack_add_mapping (primer, 0x3217, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ASPECT_RATIO), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->aspect_ratio.n); |
| GST_WRITE_UINT32_BE (t->data + 4, self->aspect_ratio.d); |
| mxf_primer_pack_add_mapping (primer, 0x320e, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->active_format_descriptor != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ACTIVE_FORMAT_DESCRIPTOR), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->active_format_descriptor); |
| mxf_primer_pack_add_mapping (primer, 0x3218, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (VIDEO_LINE_MAP), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, 2); |
| GST_WRITE_UINT32_BE (t->data + 4, 4); |
| GST_WRITE_UINT32_BE (t->data + 8, self->video_line_map[0]); |
| GST_WRITE_UINT32_BE (t->data + 12, self->video_line_map[1]); |
| mxf_primer_pack_add_mapping (primer, 0x320d, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->alpha_transparency != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ALPHA_TRANSPARENCY), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->alpha_transparency); |
| mxf_primer_pack_add_mapping (primer, 0x320f, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_ul_is_zero (&self->capture_gamma)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (CAPTURE_GAMMA), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->capture_gamma, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3210, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->image_alignment_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (IMAGE_ALIGNMENT_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->image_alignment_offset); |
| mxf_primer_pack_add_mapping (primer, 0x3211, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->image_start_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (IMAGE_START_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->image_start_offset); |
| mxf_primer_pack_add_mapping (primer, 0x3213, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->image_end_offset != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (IMAGE_END_OFFSET), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->image_end_offset); |
| mxf_primer_pack_add_mapping (primer, 0x3214, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->field_dominance != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (FIELD_DOMINANCE), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->field_dominance); |
| mxf_primer_pack_add_mapping (primer, 0x3212, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_ul_is_zero (&self->picture_essence_coding)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PICTURE_ESSENCE_CODING), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->picture_essence_coding, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3201, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_generic_picture_essence_descriptor_init |
| (MXFMetadataGenericPictureEssenceDescriptor * self) |
| { |
| self->signal_standard = 1; |
| self->frame_layout = 255; |
| } |
| |
| static void |
| mxf_metadata_generic_picture_essence_descriptor_class_init |
| (MXFMetadataGenericPictureEssenceDescriptorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = |
| mxf_metadata_generic_picture_essence_descriptor_handle_tag; |
| metadata_base_class->name_quark = |
| MXF_QUARK (GENERIC_PICTURE_ESSENCE_DESCRIPTOR); |
| metadata_base_class->to_structure = |
| mxf_metadata_generic_picture_essence_descriptor_to_structure; |
| metadata_base_class->write_tags = |
| mxf_metadata_generic_picture_essence_descriptor_write_tags; |
| metadata_class->type = 0x0127; |
| } |
| |
| void mxf_metadata_generic_picture_essence_descriptor_set_caps |
| (MXFMetadataGenericPictureEssenceDescriptor * self, GstCaps * caps) |
| { |
| guint par_n, par_d; |
| guint width, height; |
| MXFMetadataFileDescriptor *f = (MXFMetadataFileDescriptor *) self; |
| |
| g_return_if_fail (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (self)); |
| g_return_if_fail (GST_IS_CAPS (caps)); |
| |
| if (f->sample_rate.d == 0) { |
| GST_ERROR ("Invalid framerate"); |
| } else { |
| gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, f->sample_rate.n, |
| f->sample_rate.d, NULL); |
| } |
| |
| width = self->stored_width; |
| height = self->stored_height; |
| if (self->sampled_width && self->sampled_height) { |
| width = self->sampled_width; |
| height = self->sampled_height; |
| } |
| if (self->display_width && self->display_height) { |
| width = self->display_width; |
| height = self->display_height; |
| } |
| |
| /* If the video is stored as separate fields the |
| * height is only the height of one field, i.e. |
| * half the height of the frame. |
| * |
| * See SMPTE 377M E2.2 and E1.2 |
| */ |
| if (self->frame_layout == 1 || self->frame_layout == 2 |
| || self->frame_layout == 4) { |
| height *= 2; |
| gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL); |
| |
| if (self->field_dominance == 2) { |
| gst_caps_set_simple (caps, "field-order", G_TYPE_STRING, |
| "bottom-field-first", NULL); |
| } else { |
| gst_caps_set_simple (caps, "field-order", G_TYPE_STRING, |
| "top-field-first", NULL); |
| } |
| } |
| |
| if (width == 0 || height == 0) { |
| GST_ERROR ("Invalid width/height"); |
| return; |
| } |
| |
| gst_caps_set_simple (caps, "width", G_TYPE_INT, width, "height", G_TYPE_INT, |
| height, NULL); |
| |
| if (self->aspect_ratio.n == 0 && self->aspect_ratio.d == 0) { |
| gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, |
| 1, 1, NULL); |
| } else if (self->aspect_ratio.n == 0 || self->aspect_ratio.d == 0) { |
| GST_ERROR ("Invalid aspect ratio"); |
| } else { |
| par_n = height * self->aspect_ratio.n; |
| par_d = width * self->aspect_ratio.d; |
| |
| gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, |
| par_n, par_d, NULL); |
| } |
| } |
| |
| static gint |
| gst_greatest_common_divisor (gint a, gint b) |
| { |
| while (b != 0) { |
| int temp = a; |
| |
| a = b; |
| b = temp % b; |
| } |
| |
| return ABS (a); |
| } |
| |
| gboolean |
| mxf_metadata_generic_picture_essence_descriptor_from_caps |
| (MXFMetadataGenericPictureEssenceDescriptor * self, GstCaps * caps) { |
| gint par_n, par_d, gcd; |
| gint width, height; |
| gint fps_n, fps_d; |
| MXFMetadataFileDescriptor *f = (MXFMetadataFileDescriptor *) self; |
| GstStructure *s; |
| gboolean interlaced = FALSE; |
| const gchar *field_order = NULL; |
| |
| g_return_val_if_fail (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR |
| (self), FALSE); |
| g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); |
| |
| s = gst_caps_get_structure (caps, 0); |
| |
| if (!gst_structure_get_boolean (s, "interlaced", &interlaced) || !interlaced) { |
| self->frame_layout = 0; |
| } else { |
| self->frame_layout = 3; |
| field_order = gst_structure_get_string (s, "field-order"); |
| if (!field_order || strcmp (field_order, "top-field-first") == 0) |
| self->field_dominance = 1; |
| else |
| self->field_dominance = 2; |
| } |
| |
| if (!gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)) { |
| GST_ERROR ("Invalid framerate"); |
| return FALSE; |
| } |
| f->sample_rate.n = fps_n; |
| f->sample_rate.d = fps_d; |
| |
| if (!gst_structure_get_int (s, "width", &width) || |
| !gst_structure_get_int (s, "height", &height)) { |
| GST_ERROR ("Invalid width/height"); |
| return FALSE; |
| } |
| |
| self->stored_width = width; |
| self->stored_height = height; |
| |
| if (!gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d)) { |
| par_n = 1; |
| par_d = 1; |
| } |
| |
| self->aspect_ratio.n = par_n * width; |
| self->aspect_ratio.d = par_d * height; |
| gcd = |
| gst_greatest_common_divisor (self->aspect_ratio.n, self->aspect_ratio.d); |
| self->aspect_ratio.n /= gcd; |
| self->aspect_ratio.d /= gcd; |
| |
| return TRUE; |
| } |
| |
| |
| G_DEFINE_TYPE (MXFMetadataGenericSoundEssenceDescriptor, |
| mxf_metadata_generic_sound_essence_descriptor, |
| MXF_TYPE_METADATA_FILE_DESCRIPTOR); |
| |
| static gboolean |
| mxf_metadata_generic_sound_essence_descriptor_handle_tag (MXFMetadataBase * |
| metadata, MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataGenericSoundEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x3d03: |
| if (!mxf_fraction_parse (&self->audio_sampling_rate, tag_data, tag_size)) |
| goto error; |
| GST_DEBUG (" audio sampling rate = %d/%d", |
| self->audio_sampling_rate.n, self->audio_sampling_rate.d); |
| break; |
| case 0x3d02: |
| if (tag_size != 1) |
| goto error; |
| self->locked = (GST_READ_UINT8 (tag_data) != 0); |
| GST_DEBUG (" locked = %s", (self->locked) ? "yes" : "no"); |
| break; |
| case 0x3d04: |
| if (tag_size != 1) |
| goto error; |
| self->audio_ref_level = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" audio ref level = %d", self->audio_ref_level); |
| break; |
| case 0x3d05: |
| if (tag_size != 1) |
| goto error; |
| self->electro_spatial_formulation = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" electro spatial formulation = %u", |
| self->electro_spatial_formulation); |
| break; |
| case 0x3d07: |
| if (tag_size != 4) |
| goto error; |
| self->channel_count = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" channel count = %u", self->channel_count); |
| break; |
| case 0x3d01: |
| if (tag_size != 4) |
| goto error; |
| self->quantization_bits = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" quantization bits = %u", self->quantization_bits); |
| break; |
| case 0x3d0c: |
| if (tag_size != 1) |
| goto error; |
| self->dial_norm = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" dial norm = %d", self->dial_norm); |
| break; |
| case 0x3d06: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->sound_essence_compression, tag_data, 16); |
| GST_DEBUG (" sound essence compression = %s", |
| mxf_ul_to_string (&self->sound_essence_compression, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_sound_essence_descriptor_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR |
| ("Invalid generic sound essence descriptor local tag 0x%04x of size %u", |
| tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_generic_sound_essence_descriptor_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_sound_essence_descriptor_parent_class)->to_structure |
| (m); |
| MXFMetadataGenericSoundEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (AUDIO_SAMPLING_RATE), GST_TYPE_FRACTION, |
| self->audio_sampling_rate.n, self->audio_sampling_rate.d, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (LOCKED), G_TYPE_BOOLEAN, self->locked, |
| NULL); |
| |
| if (self->electro_spatial_formulation != 0) |
| gst_structure_id_set (ret, MXF_QUARK (ELECTRO_SPATIAL_FORMULATION), |
| G_TYPE_UCHAR, self->electro_spatial_formulation, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (CHANNEL_COUNT), G_TYPE_UINT, |
| self->channel_count, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (QUANTIZATION_BITS), G_TYPE_UINT, |
| self->quantization_bits, NULL); |
| |
| if (self->dial_norm != 0) |
| gst_structure_id_set (ret, MXF_QUARK (DIAL_NORM), G_TYPE_CHAR, |
| self->dial_norm, NULL); |
| |
| if (!mxf_ul_is_zero (&self->sound_essence_compression)) { |
| gchar str[48]; |
| |
| mxf_ul_to_string (&self->sound_essence_compression, str); |
| gst_structure_id_set (ret, MXF_QUARK (SOUND_ESSENCE_COMPRESSION), |
| G_TYPE_STRING, str, NULL); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_generic_sound_essence_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataGenericSoundEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_sound_essence_descriptor_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (AUDIO_SAMPLING_RATE), 16); |
| t->size = 8; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->audio_sampling_rate.n); |
| GST_WRITE_UINT32_BE (t->data + 4, self->audio_sampling_rate.d); |
| mxf_primer_pack_add_mapping (primer, 0x3d03, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (LOCKED), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, (self->locked) ? 1 : 0); |
| mxf_primer_pack_add_mapping (primer, 0x3d02, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->audio_ref_level) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (AUDIO_REF_LEVEL), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->audio_ref_level); |
| mxf_primer_pack_add_mapping (primer, 0x3d04, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->electro_spatial_formulation != 255) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ELECTRO_SPATIAL_FORMULATION), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->electro_spatial_formulation); |
| mxf_primer_pack_add_mapping (primer, 0x3d05, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (CHANNEL_COUNT), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->channel_count); |
| mxf_primer_pack_add_mapping (primer, 0x3d07, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (QUANTIZATION_BITS), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->quantization_bits); |
| mxf_primer_pack_add_mapping (primer, 0x3d01, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->dial_norm != 0) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DIAL_NORM), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->dial_norm); |
| mxf_primer_pack_add_mapping (primer, 0x3d0c, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (!mxf_ul_is_zero (&self->sound_essence_compression)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SOUND_ESSENCE_COMPRESSION), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->sound_essence_compression, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3d06, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_generic_sound_essence_descriptor_init |
| (MXFMetadataGenericSoundEssenceDescriptor * self) |
| { |
| self->audio_sampling_rate.n = 0; |
| self->audio_sampling_rate.d = 1; |
| self->electro_spatial_formulation = 255; |
| } |
| |
| static void |
| mxf_metadata_generic_sound_essence_descriptor_class_init |
| (MXFMetadataGenericSoundEssenceDescriptorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = |
| mxf_metadata_generic_sound_essence_descriptor_handle_tag; |
| metadata_base_class->name_quark = |
| MXF_QUARK (GENERIC_SOUND_ESSENCE_DESCRIPTOR); |
| metadata_base_class->to_structure = |
| mxf_metadata_generic_sound_essence_descriptor_to_structure; |
| metadata_base_class->write_tags = |
| mxf_metadata_generic_sound_essence_descriptor_write_tags; |
| metadata_class->type = 0x0142; |
| } |
| |
| void mxf_metadata_generic_sound_essence_descriptor_set_caps |
| (MXFMetadataGenericSoundEssenceDescriptor * self, GstCaps * caps) |
| { |
| g_return_if_fail (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (self)); |
| g_return_if_fail (GST_IS_CAPS (caps)); |
| |
| if (self->audio_sampling_rate.n == 0 || self->audio_sampling_rate.d == 0) { |
| GST_ERROR ("Invalid audio sampling rate"); |
| } else { |
| gst_caps_set_simple (caps, "rate", G_TYPE_INT, |
| (gint) (mxf_fraction_to_double (&self->audio_sampling_rate) + 0.5), |
| NULL); |
| } |
| |
| if (self->channel_count == 0) { |
| GST_ERROR ("Invalid number of channels (0)"); |
| } else { |
| gst_caps_set_simple (caps, "channels", G_TYPE_INT, self->channel_count, |
| NULL); |
| } |
| } |
| |
| GstCaps *mxf_metadata_generic_sound_essence_descriptor_create_caps |
| (MXFMetadataGenericSoundEssenceDescriptor * self, GstAudioFormat * format) |
| { |
| GstAudioInfo info; |
| gint rate = 0; |
| gint channels = 0; |
| |
| g_return_val_if_fail (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (self), |
| NULL); |
| |
| gst_audio_info_init (&info); |
| |
| if (self->audio_sampling_rate.n == 0 || self->audio_sampling_rate.d == 0) { |
| GST_ERROR ("Invalid audio sampling rate"); |
| } else { |
| rate = (gint) (mxf_fraction_to_double (&self->audio_sampling_rate) |
| + 0.5); |
| } |
| |
| if (self->channel_count == 0) { |
| GST_ERROR ("Invalid number of channels (0)"); |
| } else { |
| channels = self->channel_count; |
| } |
| |
| gst_audio_info_set_format (&info, *format, rate, channels, NULL); |
| |
| return gst_audio_info_to_caps (&info); |
| } |
| |
| gboolean |
| mxf_metadata_generic_sound_essence_descriptor_from_caps |
| (MXFMetadataGenericSoundEssenceDescriptor * self, GstCaps * caps) { |
| gint rate; |
| gint channels; |
| GstStructure *s; |
| |
| g_return_val_if_fail (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (self), |
| FALSE); |
| g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); |
| |
| s = gst_caps_get_structure (caps, 0); |
| |
| if (!gst_structure_get_int (s, "rate", &rate) || rate == 0) { |
| GST_WARNING ("No samplerate"); |
| return FALSE; |
| } else { |
| self->audio_sampling_rate.n = rate; |
| self->audio_sampling_rate.d = 1; |
| } |
| |
| if (!gst_structure_get_int (s, "channels", &channels) || channels == 0) { |
| GST_WARNING ("No channels"); |
| return FALSE; |
| } else { |
| self->channel_count = channels; |
| } |
| |
| return TRUE; |
| } |
| |
| |
| G_DEFINE_TYPE (MXFMetadataCDCIPictureEssenceDescriptor, |
| mxf_metadata_cdci_picture_essence_descriptor, |
| MXF_TYPE_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR); |
| |
| static gboolean |
| mxf_metadata_cdci_picture_essence_descriptor_handle_tag (MXFMetadataBase * |
| metadata, MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataCDCIPictureEssenceDescriptor *self = |
| MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x3301: |
| if (tag_size != 4) |
| goto error; |
| self->component_depth = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" component depth = %u", self->component_depth); |
| break; |
| case 0x3302: |
| if (tag_size != 4) |
| goto error; |
| self->horizontal_subsampling = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" horizontal subsampling = %u", self->horizontal_subsampling); |
| break; |
| case 0x3308: |
| if (tag_size != 4) |
| goto error; |
| self->vertical_subsampling = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" vertical subsampling = %u", self->vertical_subsampling); |
| break; |
| case 0x3303: |
| if (tag_size != 1) |
| goto error; |
| self->color_siting = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" color siting = %u", self->color_siting); |
| break; |
| case 0x330b: |
| if (tag_size != 1) |
| goto error; |
| self->reversed_byte_order = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" reversed byte order = %s", |
| (self->reversed_byte_order) ? "yes" : "no"); |
| break; |
| case 0x3307: |
| if (tag_size != 2) |
| goto error; |
| self->padding_bits = GST_READ_UINT16_BE (tag_data); |
| GST_DEBUG (" padding bits = %d", self->padding_bits); |
| break; |
| case 0x3309: |
| if (tag_size != 4) |
| goto error; |
| self->alpha_sample_depth = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" alpha sample depth = %u", self->alpha_sample_depth); |
| break; |
| case 0x3304: |
| if (tag_size != 4) |
| goto error; |
| self->black_ref_level = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" black ref level = %u", self->black_ref_level); |
| break; |
| case 0x3305: |
| if (tag_size != 4) |
| goto error; |
| self->white_ref_level = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" white ref level = %u", self->white_ref_level); |
| break; |
| case 0x3306: |
| if (tag_size != 4) |
| goto error; |
| self->color_range = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" color range = %u", self->color_range); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_cdci_picture_essence_descriptor_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR |
| ("Invalid CDCI picture essence descriptor local tag 0x%04x of size %u", |
| tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_cdci_picture_essence_descriptor_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_cdci_picture_essence_descriptor_parent_class)->to_structure |
| (m); |
| MXFMetadataCDCIPictureEssenceDescriptor *self = |
| MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (COMPONENT_DEPTH), G_TYPE_UINT, |
| self->component_depth, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (HORIZONTAL_SUBSAMPLING), G_TYPE_UINT, |
| self->horizontal_subsampling, NULL); |
| |
| if (self->vertical_subsampling != 0) |
| gst_structure_id_set (ret, MXF_QUARK (VERTICAL_SUBSAMPLING), G_TYPE_UINT, |
| self->vertical_subsampling, NULL); |
| |
| if (self->color_siting != 255) |
| gst_structure_id_set (ret, MXF_QUARK (COLOR_SITING), G_TYPE_UCHAR, |
| self->color_siting, NULL); |
| |
| gst_structure_id_set (ret, MXF_QUARK (REVERSED_BYTE_ORDER), G_TYPE_BOOLEAN, |
| self->reversed_byte_order, NULL); |
| |
| if (self->padding_bits != 0) |
| gst_structure_id_set (ret, MXF_QUARK (PADDING_BITS), G_TYPE_INT, |
| self->padding_bits, NULL); |
| |
| if (self->alpha_sample_depth != 0) |
| gst_structure_id_set (ret, MXF_QUARK (ALPHA_SAMPLE_DEPTH), G_TYPE_UINT, |
| self->alpha_sample_depth, NULL); |
| |
| if (self->black_ref_level != 0) |
| gst_structure_id_set (ret, MXF_QUARK (BLACK_REF_LEVEL), G_TYPE_UINT, |
| self->black_ref_level, NULL); |
| |
| if (self->white_ref_level != 0) |
| gst_structure_id_set (ret, MXF_QUARK (WHITE_REF_LEVEL), G_TYPE_UINT, |
| self->white_ref_level, NULL); |
| |
| if (self->color_range != 0) |
| gst_structure_id_set (ret, MXF_QUARK (COLOR_RANGE), G_TYPE_UINT, |
| self->color_range, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_cdci_picture_essence_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataCDCIPictureEssenceDescriptor *self = |
| MXF_METADATA_CDCI_PICTURE_ESSENCE_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_cdci_picture_essence_descriptor_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (COMPONENT_DEPTH), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->component_depth); |
| mxf_primer_pack_add_mapping (primer, 0x3301, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (HORIZONTAL_SUBSAMPLING), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->horizontal_subsampling); |
| mxf_primer_pack_add_mapping (primer, 0x3302, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| if (self->vertical_subsampling) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (VERTICAL_SUBSAMPLING), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->vertical_subsampling); |
| mxf_primer_pack_add_mapping (primer, 0x3308, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->color_siting != 0xff) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (COLOR_SITING), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->color_siting); |
| mxf_primer_pack_add_mapping (primer, 0x3303, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->reversed_byte_order) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (REVERSED_BYTE_ORDER), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, (self->reversed_byte_order) ? 1 : 0); |
| mxf_primer_pack_add_mapping (primer, 0x330b, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->padding_bits) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PADDING_BITS), 16); |
| t->size = 2; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT16_BE (t->data, self->padding_bits); |
| mxf_primer_pack_add_mapping (primer, 0x3307, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->alpha_sample_depth) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ALPHA_SAMPLE_DEPTH), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->alpha_sample_depth); |
| mxf_primer_pack_add_mapping (primer, 0x3309, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->black_ref_level) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (BLACK_REF_LEVEL), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->black_ref_level); |
| mxf_primer_pack_add_mapping (primer, 0x3304, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->white_ref_level) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (WHITE_REF_LEVEL), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->white_ref_level); |
| mxf_primer_pack_add_mapping (primer, 0x3305, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->color_range) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (COLOR_RANGE), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->color_range); |
| mxf_primer_pack_add_mapping (primer, 0x3306, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_cdci_picture_essence_descriptor_init |
| (MXFMetadataCDCIPictureEssenceDescriptor * self) |
| { |
| self->color_siting = 0xff; |
| } |
| |
| static void |
| mxf_metadata_cdci_picture_essence_descriptor_class_init |
| (MXFMetadataCDCIPictureEssenceDescriptorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = |
| mxf_metadata_cdci_picture_essence_descriptor_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (CDCI_PICTURE_ESSENCE_DESCRIPTOR); |
| metadata_base_class->to_structure = |
| mxf_metadata_cdci_picture_essence_descriptor_to_structure; |
| metadata_base_class->write_tags = |
| mxf_metadata_cdci_picture_essence_descriptor_write_tags; |
| metadata_class->type = 0x0128; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataRGBAPictureEssenceDescriptor, |
| mxf_metadata_rgba_picture_essence_descriptor, |
| MXF_TYPE_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR); |
| |
| static void |
| mxf_metadata_rgba_picture_essence_descriptor_finalize (GObject * object) |
| { |
| MXFMetadataRGBAPictureEssenceDescriptor *self = |
| MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR (object); |
| |
| g_free (self->pixel_layout); |
| self->pixel_layout = NULL; |
| |
| G_OBJECT_CLASS |
| (mxf_metadata_rgba_picture_essence_descriptor_parent_class)->finalize |
| (object); |
| } |
| |
| static gboolean |
| mxf_metadata_rgba_picture_essence_descriptor_handle_tag (MXFMetadataBase * |
| metadata, MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataRGBAPictureEssenceDescriptor *self = |
| MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x3406: |
| if (tag_size != 4) |
| goto error; |
| self->component_max_ref = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" component max ref = %u", self->component_max_ref); |
| break; |
| case 0x3407: |
| if (tag_size != 4) |
| goto error; |
| self->component_min_ref = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" component min ref = %u", self->component_min_ref); |
| break; |
| case 0x3408: |
| if (tag_size != 4) |
| goto error; |
| self->alpha_max_ref = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" alpha max ref = %u", self->alpha_max_ref); |
| break; |
| case 0x3409: |
| if (tag_size != 4) |
| goto error; |
| self->alpha_min_ref = GST_READ_UINT32_BE (tag_data); |
| GST_DEBUG (" alpha min ref = %u", self->alpha_min_ref); |
| break; |
| case 0x3405: |
| if (tag_size != 1) |
| goto error; |
| self->scanning_direction = GST_READ_UINT8 (tag_data); |
| GST_DEBUG (" scanning direction = %u", self->scanning_direction); |
| break; |
| case 0x3401:{ |
| guint i, len; |
| |
| if (tag_size % 2 != 0 || tag_size > 16) |
| goto error; |
| |
| i = 0; |
| while (tag_data[i] != 0 && tag_data[i + 1] != 0 && i + 2 <= tag_size) |
| i += 2; |
| len = i / 2; |
| |
| self->n_pixel_layout = len; |
| GST_DEBUG (" number of pixel layouts = %u", len); |
| if (len == 0) |
| return TRUE; |
| |
| self->pixel_layout = g_malloc0 (16); |
| |
| for (i = 0; i < len; i++) { |
| self->pixel_layout[2 * i] = tag_data[2 * i]; |
| self->pixel_layout[2 * i + 1] = tag_data[2 * i + 1]; |
| GST_DEBUG (" pixel layout %u = %c : %u", i, |
| (gchar) self->pixel_layout[2 * i], self->pixel_layout[2 * i + 1]); |
| } |
| |
| break; |
| } |
| case 0x3403: |
| case 0x3404: |
| /* TODO: handle this */ |
| GST_WARNING (" tag 0x%04x not implemented yet", tag); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_rgba_picture_essence_descriptor_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR |
| ("Invalid RGBA picture essence descriptor local tag 0x%04x of size %u", |
| tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_rgba_picture_essence_descriptor_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_rgba_picture_essence_descriptor_parent_class)->to_structure |
| (m); |
| MXFMetadataRGBAPictureEssenceDescriptor *self = |
| MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR (m); |
| |
| if (self->component_max_ref != 255) |
| gst_structure_id_set (ret, MXF_QUARK (COMPONENT_MAX_REF), G_TYPE_UINT, |
| self->component_max_ref, NULL); |
| |
| if (self->component_min_ref != 0) |
| gst_structure_id_set (ret, MXF_QUARK (COMPONENT_MIN_REF), G_TYPE_UINT, |
| self->component_min_ref, NULL); |
| |
| if (self->alpha_max_ref != 255) |
| gst_structure_id_set (ret, MXF_QUARK (ALPHA_MAX_REF), G_TYPE_UINT, |
| self->alpha_max_ref, NULL); |
| |
| if (self->alpha_min_ref != 0) |
| gst_structure_id_set (ret, MXF_QUARK (ALPHA_MIN_REF), G_TYPE_UINT, |
| self->alpha_min_ref, NULL); |
| |
| if (self->scanning_direction != 0) |
| gst_structure_id_set (ret, MXF_QUARK (SCANNING_DIRECTION), G_TYPE_UCHAR, |
| self->scanning_direction, NULL); |
| |
| if (self->n_pixel_layout != 0) { |
| gchar *pl = g_new0 (gchar, self->n_pixel_layout * 2 + 1); |
| |
| memcpy (pl, self->pixel_layout, self->n_pixel_layout * 2); |
| |
| gst_structure_id_set (ret, MXF_QUARK (PIXEL_LAYOUT), G_TYPE_STRING, pl, |
| NULL); |
| |
| g_free (pl); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_rgba_picture_essence_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataRGBAPictureEssenceDescriptor *self = |
| MXF_METADATA_RGBA_PICTURE_ESSENCE_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_rgba_picture_essence_descriptor_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->component_max_ref != 255) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (COMPONENT_MAX_REF), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->component_max_ref); |
| mxf_primer_pack_add_mapping (primer, 0x3406, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->component_min_ref) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (COMPONENT_MIN_REF), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->component_min_ref); |
| mxf_primer_pack_add_mapping (primer, 0x3407, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->alpha_max_ref != 255) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ALPHA_MAX_REF), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->alpha_max_ref); |
| mxf_primer_pack_add_mapping (primer, 0x3408, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->alpha_min_ref) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (ALPHA_MIN_REF), 16); |
| t->size = 4; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->alpha_min_ref); |
| mxf_primer_pack_add_mapping (primer, 0x3409, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| if (self->scanning_direction) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SCANNING_DIRECTION), 16); |
| t->size = 1; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT8 (t->data, self->scanning_direction); |
| mxf_primer_pack_add_mapping (primer, 0x3405, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (PIXEL_LAYOUT), 16); |
| t->size = 16; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| if (self->pixel_layout) |
| memcpy (t->data, self->pixel_layout, self->n_pixel_layout * 2); |
| mxf_primer_pack_add_mapping (primer, 0x3401, &t->ul); |
| ret = g_list_prepend (ret, t); |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_rgba_picture_essence_descriptor_init |
| (MXFMetadataRGBAPictureEssenceDescriptor * self) |
| { |
| self->component_max_ref = 255; |
| self->alpha_max_ref = 255; |
| } |
| |
| static void |
| mxf_metadata_rgba_picture_essence_descriptor_class_init |
| (MXFMetadataRGBAPictureEssenceDescriptorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = |
| mxf_metadata_rgba_picture_essence_descriptor_finalize; |
| metadata_base_class->handle_tag = |
| mxf_metadata_rgba_picture_essence_descriptor_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (RGBA_PICTURE_ESSENCE_DESCRIPTOR); |
| metadata_base_class->to_structure = |
| mxf_metadata_rgba_picture_essence_descriptor_to_structure; |
| metadata_base_class->write_tags = |
| mxf_metadata_rgba_picture_essence_descriptor_write_tags; |
| metadata_class->type = 0x0129; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataGenericDataEssenceDescriptor, |
| mxf_metadata_generic_data_essence_descriptor, |
| MXF_TYPE_METADATA_FILE_DESCRIPTOR); |
| |
| static gboolean |
| mxf_metadata_generic_data_essence_descriptor_handle_tag (MXFMetadataBase * |
| metadata, MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataGenericDataEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x3e01: |
| if (tag_size != 16) |
| goto error; |
| memcpy (&self->data_essence_coding, tag_data, 16); |
| GST_DEBUG (" data essence coding = %s", |
| mxf_ul_to_string (&self->data_essence_coding, str)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_data_essence_descriptor_parent_class)->handle_tag |
| (metadata, primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR |
| ("Invalid generic data essence descriptor local tag 0x%04x of size %u", |
| tag, tag_size); |
| |
| return FALSE; |
| } |
| |
| static GstStructure * |
| mxf_metadata_generic_data_essence_descriptor_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_data_essence_descriptor_parent_class)->to_structure |
| (m); |
| MXFMetadataGenericDataEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (m); |
| gchar str[48]; |
| |
| if (!mxf_ul_is_zero (&self->data_essence_coding)) { |
| mxf_ul_to_string (&self->data_essence_coding, str); |
| gst_structure_id_set (ret, MXF_QUARK (DATA_ESSENCE_CODING), G_TYPE_STRING, |
| str, NULL); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_generic_data_essence_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataGenericDataEssenceDescriptor *self = |
| MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_generic_data_essence_descriptor_parent_class)->write_tags |
| (m, primer); |
| MXFLocalTag *t; |
| |
| if (!mxf_ul_is_zero (&self->data_essence_coding)) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (DATA_ESSENCE_CODING), 16); |
| t->size = 16; |
| t->data = g_slice_alloc (t->size); |
| t->g_slice = TRUE; |
| memcpy (t->data, &self->data_essence_coding, 16); |
| mxf_primer_pack_add_mapping (primer, 0x3e01, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_generic_data_essence_descriptor_init |
| (MXFMetadataGenericDataEssenceDescriptor * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_generic_data_essence_descriptor_class_init |
| (MXFMetadataGenericDataEssenceDescriptorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| metadata_base_class->handle_tag = |
| mxf_metadata_generic_data_essence_descriptor_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (GENERIC_DATA_ESSENCE_DESCRIPTOR); |
| metadata_base_class->to_structure = |
| mxf_metadata_generic_data_essence_descriptor_to_structure; |
| metadata_base_class->write_tags = |
| mxf_metadata_generic_data_essence_descriptor_write_tags; |
| metadata_class->type = 0x0143; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataMultipleDescriptor, mxf_metadata_multiple_descriptor, |
| MXF_TYPE_METADATA_FILE_DESCRIPTOR); |
| |
| static void |
| mxf_metadata_multiple_descriptor_finalize (GObject * object) |
| { |
| MXFMetadataMultipleDescriptor *self = |
| MXF_METADATA_MULTIPLE_DESCRIPTOR (object); |
| |
| g_free (self->sub_descriptors_uids); |
| self->sub_descriptors_uids = NULL; |
| g_free (self->sub_descriptors); |
| self->sub_descriptors = NULL; |
| |
| G_OBJECT_CLASS |
| (mxf_metadata_multiple_descriptor_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_multiple_descriptor_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataMultipleDescriptor *self = |
| MXF_METADATA_MULTIPLE_DESCRIPTOR (metadata); |
| gboolean ret = TRUE; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| switch (tag) { |
| case 0x3f01: |
| if (!mxf_uuid_array_parse (&self->sub_descriptors_uids, |
| &self->n_sub_descriptors, tag_data, tag_size)) |
| goto error; |
| |
| GST_DEBUG (" number of sub descriptors = %u", self->n_sub_descriptors); |
| #ifndef GST_DISABLE_GST_DEBUG |
| { |
| guint i; |
| for (i = 0; i < self->n_sub_descriptors; i++) { |
| GST_DEBUG (" sub descriptor %u = %s", i, |
| mxf_uuid_to_string (&self->sub_descriptors_uids[i], str)); |
| } |
| } |
| #endif |
| |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_multiple_descriptor_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| |
| error: |
| |
| GST_ERROR ("Invalid multiple descriptor local tag 0x%04x of size %u", tag, |
| tag_size); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| mxf_metadata_multiple_descriptor_resolve (MXFMetadataBase * m, |
| GHashTable * metadata) |
| { |
| MXFMetadataMultipleDescriptor *self = MXF_METADATA_MULTIPLE_DESCRIPTOR (m); |
| MXFMetadataBase *current = NULL; |
| guint i, have_subdescriptors = 0; |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar str[48]; |
| #endif |
| |
| if (self->sub_descriptors) |
| memset (self->sub_descriptors, 0, |
| sizeof (gpointer) * self->n_sub_descriptors); |
| else |
| self->sub_descriptors = |
| g_new0 (MXFMetadataGenericDescriptor *, self->n_sub_descriptors); |
| for (i = 0; i < self->n_sub_descriptors; i++) { |
| current = g_hash_table_lookup (metadata, &self->sub_descriptors_uids[i]); |
| if (current && MXF_IS_METADATA_GENERIC_DESCRIPTOR (current)) { |
| if (mxf_metadata_base_resolve (current, metadata)) { |
| self->sub_descriptors[i] = MXF_METADATA_GENERIC_DESCRIPTOR (current); |
| have_subdescriptors++; |
| } else { |
| GST_ERROR ("Couldn't resolve descriptor %s", |
| mxf_uuid_to_string (&self->sub_descriptors_uids[i], str)); |
| return FALSE; |
| } |
| } else { |
| GST_ERROR ("Descriptor %s not found", |
| mxf_uuid_to_string (&self->sub_descriptors_uids[i], str)); |
| } |
| } |
| |
| return |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_multiple_descriptor_parent_class)->resolve (m, metadata); |
| } |
| |
| static GstStructure * |
| mxf_metadata_multiple_descriptor_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_multiple_descriptor_parent_class)->to_structure (m); |
| MXFMetadataMultipleDescriptor *self = MXF_METADATA_MULTIPLE_DESCRIPTOR (m); |
| guint i; |
| |
| if (self->n_sub_descriptors > 0) { |
| GValue arr = { 0, } |
| , val = { |
| 0,}; |
| |
| g_value_init (&arr, GST_TYPE_ARRAY); |
| |
| for (i = 0; i < self->n_sub_descriptors; i++) { |
| GstStructure *s; |
| |
| if (self->sub_descriptors[i] == NULL) |
| continue; |
| |
| g_value_init (&val, GST_TYPE_STRUCTURE); |
| |
| s = mxf_metadata_base_to_structure (MXF_METADATA_BASE |
| (self->sub_descriptors[i])); |
| gst_value_set_structure (&val, s); |
| gst_structure_free (s); |
| gst_value_array_append_value (&arr, &val); |
| g_value_unset (&val); |
| } |
| |
| if (gst_value_array_get_size (&arr) > 0) |
| gst_structure_id_set_value (ret, MXF_QUARK (SUB_DESCRIPTORS), &arr); |
| |
| g_value_unset (&arr); |
| } |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_multiple_descriptor_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataMultipleDescriptor *self = MXF_METADATA_MULTIPLE_DESCRIPTOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_multiple_descriptor_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->sub_descriptors) { |
| guint i; |
| |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (SUB_DESCRIPTORS), 16); |
| t->size = 8 + 16 * self->n_sub_descriptors; |
| t->data = g_slice_alloc0 (t->size); |
| t->g_slice = TRUE; |
| GST_WRITE_UINT32_BE (t->data, self->n_sub_descriptors); |
| GST_WRITE_UINT32_BE (t->data + 4, 16); |
| for (i = 0; i < self->n_sub_descriptors; i++) { |
| if (!self->sub_descriptors[i]) |
| continue; |
| |
| memcpy (t->data + 8 + 16 * i, |
| &MXF_METADATA_BASE (self->sub_descriptors[i])->instance_uid, 16); |
| } |
| mxf_primer_pack_add_mapping (primer, 0x3f01, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_multiple_descriptor_init (MXFMetadataMultipleDescriptor * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_multiple_descriptor_class_init (MXFMetadataMultipleDescriptorClass |
| * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_multiple_descriptor_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_multiple_descriptor_handle_tag; |
| metadata_base_class->resolve = mxf_metadata_multiple_descriptor_resolve; |
| metadata_base_class->name_quark = MXF_QUARK (MULTIPLE_DESCRIPTOR); |
| metadata_base_class->to_structure = |
| mxf_metadata_multiple_descriptor_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_multiple_descriptor_write_tags; |
| metadata_class->type = 0x0144; |
| } |
| |
| G_DEFINE_ABSTRACT_TYPE (MXFMetadataLocator, mxf_metadata_locator, |
| MXF_TYPE_METADATA); |
| |
| static void |
| mxf_metadata_locator_init (MXFMetadataLocator * self) |
| { |
| } |
| |
| static void |
| mxf_metadata_locator_class_init (MXFMetadataLocatorClass * klass) |
| { |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataTextLocator, mxf_metadata_text_locator, |
| MXF_TYPE_METADATA_LOCATOR); |
| |
| static void |
| mxf_metadata_text_locator_finalize (GObject * object) |
| { |
| MXFMetadataTextLocator *self = MXF_METADATA_TEXT_LOCATOR (object); |
| |
| g_free (self->locator_name); |
| self->locator_name = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_text_locator_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_text_locator_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataTextLocator *self = MXF_METADATA_TEXT_LOCATOR (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x4101: |
| self->locator_name = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" text locator = %s", GST_STR_NULL (self->locator_name)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_text_locator_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static GstStructure * |
| mxf_metadata_text_locator_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_text_locator_parent_class)->to_structure (m); |
| MXFMetadataTextLocator *self = MXF_METADATA_TEXT_LOCATOR (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (LOCATOR_NAME), G_TYPE_STRING, |
| self->locator_name, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_text_locator_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataTextLocator *self = MXF_METADATA_TEXT_LOCATOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_text_locator_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->locator_name) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (LOCATOR_NAME), 16); |
| t->data = mxf_utf8_to_utf16 (self->locator_name, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x4101, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_text_locator_init (MXFMetadataTextLocator * self) |
| { |
| |
| } |
| |
| static void |
| mxf_metadata_text_locator_class_init (MXFMetadataTextLocatorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_text_locator_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_text_locator_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (TEXT_LOCATOR); |
| metadata_base_class->to_structure = mxf_metadata_text_locator_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_text_locator_write_tags; |
| metadata_class->type = 0x0133; |
| } |
| |
| G_DEFINE_TYPE (MXFMetadataNetworkLocator, mxf_metadata_network_locator, |
| MXF_TYPE_METADATA_LOCATOR); |
| |
| static void |
| mxf_metadata_network_locator_finalize (GObject * object) |
| { |
| MXFMetadataNetworkLocator *self = MXF_METADATA_NETWORK_LOCATOR (object); |
| |
| g_free (self->url_string); |
| self->url_string = NULL; |
| |
| G_OBJECT_CLASS (mxf_metadata_network_locator_parent_class)->finalize (object); |
| } |
| |
| static gboolean |
| mxf_metadata_network_locator_handle_tag (MXFMetadataBase * metadata, |
| MXFPrimerPack * primer, guint16 tag, const guint8 * tag_data, |
| guint tag_size) |
| { |
| MXFMetadataNetworkLocator *self = MXF_METADATA_NETWORK_LOCATOR (metadata); |
| gboolean ret = TRUE; |
| |
| switch (tag) { |
| case 0x4101: |
| self->url_string = mxf_utf16_to_utf8 (tag_data, tag_size); |
| GST_DEBUG (" url string = %s", GST_STR_NULL (self->url_string)); |
| break; |
| default: |
| ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_network_locator_parent_class)->handle_tag (metadata, |
| primer, tag, tag_data, tag_size); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static GstStructure * |
| mxf_metadata_network_locator_to_structure (MXFMetadataBase * m) |
| { |
| GstStructure *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_network_locator_parent_class)->to_structure (m); |
| MXFMetadataNetworkLocator *self = MXF_METADATA_NETWORK_LOCATOR (m); |
| |
| gst_structure_id_set (ret, MXF_QUARK (URL_STRING), G_TYPE_STRING, |
| self->url_string, NULL); |
| |
| return ret; |
| } |
| |
| static GList * |
| mxf_metadata_network_locator_write_tags (MXFMetadataBase * m, |
| MXFPrimerPack * primer) |
| { |
| MXFMetadataNetworkLocator *self = MXF_METADATA_NETWORK_LOCATOR (m); |
| GList *ret = |
| MXF_METADATA_BASE_CLASS |
| (mxf_metadata_network_locator_parent_class)->write_tags (m, primer); |
| MXFLocalTag *t; |
| |
| if (self->url_string) { |
| t = g_slice_new0 (MXFLocalTag); |
| memcpy (&t->ul, MXF_UL (URL_STRING), 16); |
| t->data = mxf_utf8_to_utf16 (self->url_string, &t->size); |
| mxf_primer_pack_add_mapping (primer, 0x4001, &t->ul); |
| ret = g_list_prepend (ret, t); |
| } |
| |
| return ret; |
| } |
| |
| static void |
| mxf_metadata_network_locator_init (MXFMetadataNetworkLocator * self) |
| { |
| } |
| |
| static void |
| mxf_metadata_network_locator_class_init (MXFMetadataNetworkLocatorClass * klass) |
| { |
| MXFMetadataBaseClass *metadata_base_class = (MXFMetadataBaseClass *) klass; |
| GObjectClass *object_class = (GObjectClass *) klass; |
| MXFMetadataClass *metadata_class = (MXFMetadataClass *) klass; |
| |
| object_class->finalize = mxf_metadata_network_locator_finalize; |
| metadata_base_class->handle_tag = mxf_metadata_network_locator_handle_tag; |
| metadata_base_class->name_quark = MXF_QUARK (NETWORK_LOCATOR); |
| metadata_base_class->to_structure = mxf_metadata_network_locator_to_structure; |
| metadata_base_class->write_tags = mxf_metadata_network_locator_write_tags; |
| metadata_class->type = 0x0133; |
| } |
| |
| G_DEFINE_ABSTRACT_TYPE (MXFDescriptiveMetadata, mxf_descriptive_metadata, |
| MXF_TYPE_METADATA_BASE); |
| |
| static void |
| mxf_descriptive_metadata_init (MXFDescriptiveMetadata * self) |
| { |
| } |
| |
| static void |
| mxf_descriptive_metadata_class_init (MXFDescriptiveMetadataClass * klass) |
| { |
| } |
| |
| typedef struct |
| { |
| guint8 scheme; |
| GType *types; |
| } _MXFDescriptiveMetadataScheme; |
| |
| static GArray *_dm_schemes = NULL; |
| |
| void |
| mxf_descriptive_metadata_register (guint8 scheme, GType * types) |
| { |
| _MXFDescriptiveMetadataScheme s; |
| |
| if (!_dm_schemes) |
| _dm_schemes = |
| g_array_new (FALSE, TRUE, sizeof (_MXFDescriptiveMetadataScheme)); |
| |
| s.scheme = scheme; |
| s.types = types; |
| |
| g_array_append_val (_dm_schemes, s); |
| } |
| |
| MXFDescriptiveMetadata * |
| mxf_descriptive_metadata_new (guint8 scheme, guint32 type, |
| MXFPrimerPack * primer, guint64 offset, const guint8 * data, guint size) |
| { |
| guint i; |
| GType t = G_TYPE_INVALID, *p; |
| _MXFDescriptiveMetadataScheme *s = NULL; |
| MXFDescriptiveMetadata *ret = NULL; |
| |
| g_return_val_if_fail (primer != NULL, NULL); |
| |
| if (G_UNLIKELY (type == 0)) { |
| GST_WARNING ("Type 0 is invalid"); |
| return NULL; |
| } |
| |
| for (i = 0; _dm_schemes && i < _dm_schemes->len; i++) { |
| _MXFDescriptiveMetadataScheme *data = |
| &g_array_index (_dm_schemes, _MXFDescriptiveMetadataScheme, i); |
| |
| if (data->scheme == scheme) { |
| s = data; |
| break; |
| } |
| } |
| |
| if (s == NULL) { |
| GST_WARNING ("Descriptive metadata scheme 0x%02x not supported", scheme); |
| return NULL; |
| } |
| |
| p = s->types; |
| while (*p) { |
| GType tmp = *p; |
| MXFDescriptiveMetadataClass *klass = |
| MXF_DESCRIPTIVE_METADATA_CLASS (g_type_class_ref (tmp)); |
| |
| if (klass->type == type) { |
| g_type_class_unref (klass); |
| t = tmp; |
| break; |
| } |
| g_type_class_unref (klass); |
| p++; |
| } |
| |
| if (t == G_TYPE_INVALID) { |
| GST_WARNING |
| ("No handler for type 0x%06x of descriptive metadata scheme 0x%02x found", |
| type, scheme); |
| return NULL; |
| } |
| |
| GST_DEBUG ("DM scheme 0x%02x type 0x%06x is handled by type %s", scheme, type, |
| g_type_name (t)); |
| |
| ret = (MXFDescriptiveMetadata *) g_type_create_instance (t); |
| if (!mxf_metadata_base_parse (MXF_METADATA_BASE (ret), primer, data, size)) { |
| GST_ERROR ("Parsing metadata failed"); |
| g_object_unref (ret); |
| return NULL; |
| } |
| |
| ret->parent.offset = offset; |
| |
| return ret; |
| } |
| |
| GType |
| mxf_descriptive_metadata_framework_get_type (void) |
| { |
| static volatile gsize type = 0; |
| if (g_once_init_enter (&type)) { |
| GType _type = 0; |
| static const GTypeInfo info = { |
| sizeof (MXFDescriptiveMetadataFrameworkInterface), |
| NULL, /* base_init */ |
| NULL, /* base_finalize */ |
| NULL, /* class_init */ |
| NULL, /* class_finalize */ |
| NULL, /* class_data */ |
| 0, /* instance_size */ |
| 0, /* n_preallocs */ |
| NULL /* instance_init */ |
| }; |
| _type = g_type_register_static (G_TYPE_INTERFACE, |
| "MXFDescriptiveMetadataFrameworkInterface", &info, 0); |
| |
| g_type_interface_add_prerequisite (_type, MXF_TYPE_DESCRIPTIVE_METADATA); |
| |
| g_once_init_leave (&type, (gsize) _type); |
| } |
| |
| return (GType) type; |
| } |
| |
| GHashTable * |
| mxf_metadata_hash_table_new (void) |
| { |
| return g_hash_table_new_full ((GHashFunc) mxf_uuid_hash, |
| (GEqualFunc) mxf_uuid_is_equal, (GDestroyNotify) NULL, |
| (GDestroyNotify) g_object_unref); |
| } |