| /* |
| * GStreamer |
| * Copyright 2007 Edgard Lima <edgard.lima@indt.org.br> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| * |
| * Alternatively, the contents of this file may be used under the |
| * GNU Lesser General Public License Version 2.1 (the "LGPL"), in |
| * which case the following provisions apply instead of the ones |
| * mentioned above: |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| * Boston, MA 02111-1307, USA. |
| */ |
| |
| /* |
| * SECTION: metadataxmp |
| * @short_description: This module provides functions to extract tags from |
| * XMP metadata chunks and create XMP chunks from metadata tags. |
| * @see_also: #metadatatags.[c/h] |
| * |
| * If lib exempi isn't available at compilation time, only the whole chunk |
| * (#METADATA_TAG_MAP_WHOLECHUNK) tags is created. It means that individual |
| * tags aren't mapped. |
| * |
| * <refsect2> |
| * <para> |
| * #metadata_xmp_init must be called before any other function in this |
| * module and must be paired with a call to #metadata_xmp_dispose |
| * </para> |
| * </refsect2> |
| * |
| * Last reviewed on 2008-01-24 (0.10.15) |
| */ |
| |
| /* |
| * includes |
| */ |
| |
| #include "metadataxmp.h" |
| #include "metadataparseutil.h" |
| #include "metadatatags.h" |
| |
| /* |
| * defines |
| */ |
| |
| GST_DEBUG_CATEGORY (gst_metadata_xmp_debug); |
| #define GST_CAT_DEFAULT gst_metadata_xmp_debug |
| |
| /* |
| * Implementation when lib exempi isn't available at compilation time |
| */ |
| |
| #ifndef HAVE_XMP |
| |
| /* |
| * extern functions implementations |
| */ |
| |
| gboolean |
| metadata_xmp_init (void) |
| { |
| return TRUE; |
| } |
| |
| void |
| metadata_xmp_dispose (void) |
| { |
| return; |
| } |
| |
| void |
| metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode, |
| GstAdapter * adapter, MetadataTagMapping mapping) |
| { |
| |
| if (mapping & METADATA_TAG_MAP_WHOLECHUNK) { |
| GST_LOG ("XMP not defined, sending just one tag as whole chunk"); |
| metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter); |
| } |
| |
| } |
| |
| void |
| metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 * size, |
| const GstTagList * taglist) |
| { |
| /* do nothing */ |
| } |
| |
| #else /* ifndef HAVE_XMP */ |
| |
| /* |
| * Implementation when lib exempi isn't available at compilation time |
| */ |
| |
| /* |
| * includes |
| */ |
| |
| #include <exempi/xmp.h> |
| #include <string.h> |
| |
| /* |
| * enum and types |
| */ |
| |
| typedef struct _tag_SchemaTagMap |
| { |
| const gchar *xmp_tag; |
| const gchar *gst_tag; |
| } SchemaTagMap; |
| |
| typedef struct _tag_SchemaMap |
| { |
| const gchar *schema; |
| const gchar *prefix; |
| const guint8 prefix_len; |
| const SchemaTagMap *tags_map; |
| } SchemaMap; |
| |
| /* |
| * defines and static global vars |
| */ |
| |
| #define XMP_SCHEMA_NODE 0x80000000UL |
| |
| /* *INDENT-OFF* */ |
| /* When changing these tables, update 'metadata_mapping.htm' file too. */ |
| static const SchemaTagMap schema_map_dublin_tags_map[] = { |
| {"creator", GST_TAG_ARTIST }, |
| {"description", GST_TAG_DESCRIPTION }, |
| {"format", GST_TAG_VIDEO_CODEC }, |
| {"rights", GST_TAG_COPYRIGHT }, |
| {"subject", GST_TAG_KEYWORDS }, |
| {"title", GST_TAG_TITLE }, |
| {"type", GST_TAG_CODEC }, |
| {NULL, NULL} |
| }; |
| |
| static const SchemaTagMap schema_map_photoshop_tags_map[] = { |
| {"Country", GST_TAG_XMP_GEO_LOCATION_COUNTRY }, |
| {"City", GST_TAG_XMP_GEO_LOCATION_CITY }, |
| {NULL, NULL} |
| }; |
| |
| static const SchemaTagMap schema_map_iptc4xmpcore_tags_map[] = { |
| {"location", GST_TAG_XMP_GEO_LOCATION_SUBLOCATION }, |
| {NULL, NULL} |
| }; |
| /* *INDENT-ON* */ |
| |
| static const SchemaMap schema_map_dublin = { |
| "http://purl.org/dc/elements/1.1/", |
| "dc:", |
| 3, |
| schema_map_dublin_tags_map |
| }; |
| |
| /* http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf */ |
| static const SchemaMap schema_map_photoshop = { |
| "http://ns.adobe.com/photoshop/1.0/", |
| "photoshop:", |
| 10, |
| schema_map_photoshop_tags_map |
| }; |
| |
| /* http://www.iptc.org/std/Iptc4xmpCore/1.0/specification/Iptc4xmpCore_1.0-spec-XMPSchema_8.pdf */ |
| static const SchemaMap schema_map_iptc4xmpcore = { |
| "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/", |
| "Iptc4xmpCore:", |
| 13, |
| schema_map_iptc4xmpcore_tags_map |
| }; |
| |
| static const SchemaMap *schemas_map[] = { |
| &schema_map_dublin, |
| &schema_map_photoshop, |
| &schema_map_iptc4xmpcore, |
| NULL |
| }; |
| |
| /* |
| * static helper functions declaration |
| */ |
| |
| static const SchemaTagMap *metadataparse_xmp_get_tagsmap_from_path (const |
| SchemaMap * schema_map, const gchar * path, uint32_t opt); |
| |
| static const SchemaTagMap *metadatamux_xmp_get_tagsmap_from_gsttag (const |
| SchemaMap * schema_map, const gchar * tag); |
| |
| static void |
| metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp); |
| |
| static void |
| metadataparse_xmp_iter_node_schema (GstTagList * taglist, GstTagMergeMode mode, |
| XmpPtr xmp, const char *schema, const char *path); |
| |
| static void |
| metadataparse_xmp_iter_array (GstTagList * taglist, GstTagMergeMode mode, |
| XmpPtr xmp, const char *schema, const char *path, |
| const SchemaMap * schema_map); |
| |
| static void |
| metadataparse_xmp_iter_simple_qual (GstTagList * taglist, GstTagMergeMode mode, |
| const char *path, const char *value, const SchemaMap * schema_map); |
| |
| static void |
| metadataparse_xmp_iter_simple (GstTagList * taglist, GstTagMergeMode mode, |
| const char *path, const char *value, const SchemaMap * schema_map); |
| |
| static void |
| metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist, |
| GstTagMergeMode mode, const char *path, const char *value, |
| const SchemaMap * schema_map, const uint32_t opt); |
| |
| static void |
| metadatamux_xmp_for_each_tag_in_list (const GstTagList * list, |
| const gchar * tag, gpointer user_data); |
| |
| /* |
| * extern functions implementations |
| */ |
| |
| /* |
| * metadata_xmp_init: |
| * |
| * Init lib exempi (if present in compilation time) |
| * This function must be called before any other function from this module. |
| * This function must not be called twice without call |
| * to #metadata_xmp_dispose beteween them. |
| * @see_also: #metadata_xmp_dispose |
| * |
| * Returns: nothing |
| */ |
| |
| gboolean |
| metadata_xmp_init (void) |
| { |
| return xmp_init (); |
| } |
| |
| /* |
| * metadata_xmp_dispose: |
| * |
| * Call this function to free any resource allocated by #metadata_xmp_init |
| * @see_also: #metadata_xmp_init |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadata_xmp_dispose (void) |
| { |
| xmp_terminate (); |
| } |
| |
| /* |
| * metadataparse_xmp_tag_list_add: |
| * @taglist: tag list in which extracted tags will be added |
| * @mode: tag list merge mode |
| * @adapter: contains the XMP metadata chunk |
| * @mapping: if is to extract individual tags and/or the whole chunk. |
| * |
| * This function gets a XMP chunk (@adapter) and extract tags from it |
| * and then to add to @taglist. |
| * Note: The XMP chunk (@adapetr) must NOT be wrapped by any bytes specific |
| * to any file format |
| * @see_also: #metadataparse_xmp_iter |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadataparse_xmp_tag_list_add (GstTagList * taglist, GstTagMergeMode mode, |
| GstAdapter * adapter, MetadataTagMapping mapping) |
| { |
| const guint8 *buf; |
| guint32 size; |
| XmpPtr xmp = NULL; |
| |
| if (adapter == NULL || (size = gst_adapter_available (adapter)) == 0) { |
| goto done; |
| } |
| |
| /* add chunk tag */ |
| if (mapping & METADATA_TAG_MAP_WHOLECHUNK) { |
| metadataparse_util_tag_list_add_chunk (taglist, mode, GST_TAG_XMP, adapter); |
| } |
| |
| if (!(mapping & METADATA_TAG_MAP_INDIVIDUALS)) |
| goto done; |
| |
| buf = gst_adapter_peek (adapter, size); |
| |
| xmp = xmp_new ((gchar *) buf, size); |
| if (!xmp) |
| goto done; |
| |
| metadataparse_xmp_iter (taglist, mode, xmp); |
| |
| done: |
| |
| if (xmp) { |
| xmp_free (xmp); |
| } |
| |
| return; |
| |
| } |
| |
| /* |
| * metadatamux_xmp_create_chunk_from_tag_list: |
| * @buf: buffer that will have the created XMP chunk |
| * @size: size of the buffer that will be created |
| * @taglist: list of tags to be added to XMP chunk |
| * |
| * Get tags from @taglist, create a XMP chunk based on it and save to @buf. |
| * Note: The XMP chunk is NOT wrapped by any bytes specific to any file format |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadatamux_xmp_create_chunk_from_tag_list (guint8 ** buf, guint32 * size, |
| const GstTagList * taglist) |
| { |
| GstBuffer *xmp_chunk = NULL; |
| const GValue *val = NULL; |
| XmpPtr xmp = NULL; |
| XmpStringPtr xmp_str_buf = xmp_string_new (); |
| |
| if (!(buf && size)) |
| goto done; |
| if (*buf) { |
| g_free (*buf); |
| *buf = NULL; |
| } |
| *size = 0; |
| |
| val = gst_tag_list_get_value_index (taglist, GST_TAG_XMP, 0); |
| if (val) { |
| xmp_chunk = gst_value_get_buffer (val); |
| if (xmp_chunk) |
| xmp = |
| xmp_new ((gchar *) GST_BUFFER_DATA (xmp_chunk), |
| GST_BUFFER_SIZE (xmp_chunk)); |
| } |
| |
| if (NULL == xmp) |
| xmp = xmp_new_empty (); |
| |
| gst_tag_list_foreach (taglist, metadatamux_xmp_for_each_tag_in_list, xmp); |
| |
| if (!xmp_serialize (xmp, xmp_str_buf, 0, 2)) { |
| GST_ERROR ("failed to serialize xmp into chunk\n"); |
| } else if (xmp_str_buf) { |
| unsigned int len = strlen (xmp_string_cstr (xmp_str_buf)); |
| |
| *size = len + 1; |
| *buf = malloc (*size); |
| memcpy (*buf, xmp_string_cstr (xmp_str_buf), *size); |
| } else { |
| GST_ERROR ("failed to serialize xmp into chunk\n"); |
| } |
| |
| done: |
| |
| if (xmp_str_buf) |
| xmp_string_free (xmp_str_buf); |
| |
| if (xmp) |
| xmp_free (xmp); |
| |
| return; |
| } |
| |
| /* |
| * static helper functions implementation |
| */ |
| |
| /* |
| * metadataparse_xmp_get_tagsmap_from_path: |
| * @schema_map: Structure containg a map beteween GST tags and tags into a XMP |
| * schema |
| * @path: string describing a XMP tag |
| * @opt: indicates if the string (@path) has extras caracters like '[' and ']' |
| * |
| * This returns a structure that contains the GStreamer tag mapped to an XMP |
| * tag. |
| * |
| * Returns: |
| * <itemizedlist> |
| * <listitem><para>Structure containing the GST tag mapped |
| * to the XMP tag (@path) |
| * </para></listitem> |
| * <listitem><para>%NULL if there is no mapped GST tag for XMP tag (@path) |
| * </para></listitem> |
| * </itemizedlist> |
| */ |
| |
| static const SchemaTagMap * |
| metadataparse_xmp_get_tagsmap_from_path (const SchemaMap * schema_map, |
| const gchar * path, uint32_t opt) |
| { |
| |
| GString *string = NULL; |
| gchar *ch; |
| SchemaTagMap *tags_map = NULL; |
| |
| if (NULL == schema_map) |
| goto done; |
| |
| tags_map = (SchemaTagMap *) schema_map->tags_map; |
| |
| if (XMP_HAS_PROP_QUALIFIERS (opt) || XMP_IS_ARRAY_ALTTEXT (opt)) { |
| |
| string = g_string_new (path); |
| |
| /* remove the language qualifier "[xxx]" */ |
| ch = string->str + string->len - 3; |
| while (ch != string->str + schema_map->prefix_len) { |
| if (*ch == '[') { |
| *ch = '\0'; |
| } |
| --ch; |
| } |
| |
| } else { |
| ch = (gchar *) path + schema_map->prefix_len; |
| } |
| |
| while (tags_map->xmp_tag) { |
| if (0 == strcmp (tags_map->xmp_tag, ch)) |
| break; |
| tags_map++; |
| } |
| |
| done: |
| |
| if (string) |
| g_string_free (string, TRUE); |
| |
| return tags_map; |
| |
| } |
| |
| /* |
| * metadatamux_xmp_get_tagsmap_from_gsttag: |
| * @schema_map: Structure containg a map beteween GST tags and tags into a XMP |
| * schema |
| * @tag: GStreaner tag to look for |
| * |
| * This returns a structure that contains the XMP tag mapped to a GStreamer |
| * tag. |
| * |
| * Returns: |
| * <itemizedlist> |
| * <listitem><para>Structure containing the XMP tag mapped |
| * to the GST tag (@path) |
| * </para></listitem> |
| * <listitem><para>%NULL if there is no mapped XMP tag for GST @tag |
| * </para></listitem> |
| * </itemizedlist> |
| */ |
| |
| static const SchemaTagMap * |
| metadatamux_xmp_get_tagsmap_from_gsttag (const SchemaMap * schema_map, |
| const gchar * tag) |
| { |
| SchemaTagMap *tags_map = NULL; |
| int i; |
| |
| if (NULL == schema_map) |
| goto done; |
| |
| for (i = 0; schema_map->tags_map[i].gst_tag; i++) { |
| if (0 == strcmp (schema_map->tags_map[i].gst_tag, tag)) { |
| tags_map = (SchemaTagMap *) & schema_map->tags_map[i]; |
| break; |
| } |
| } |
| |
| done: |
| |
| return tags_map; |
| |
| } |
| |
| /* |
| * metadataparse_xmp_iter: |
| * @taglist: tag list in which extracted tags will be added |
| * @mode: tag list merge mode |
| * @xmp: handle to XMP data from lib exempi |
| * |
| * This function looks all the shemas in a XMP data (@xmp) and then calls |
| * #metadataparse_xmp_iter_node_schema for each schema. In the end, the idea is |
| * to add all XMP mapped tags to @taglist by unsing a specified merge @mode |
| * @see_also: #metadataparse_xmp_tag_list_add |
| * #metadataparse_xmp_iter_node_schema |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadataparse_xmp_iter (GstTagList * taglist, GstTagMergeMode mode, XmpPtr xmp) |
| { |
| XmpStringPtr xstr_schema = xmp_string_new (); |
| XmpStringPtr xstr_path = xmp_string_new (); |
| XmpStringPtr xstr_prop = xmp_string_new (); |
| uint32_t opt = 0; |
| XmpIteratorPtr xmp_iter = NULL; |
| |
| xmp_iter = xmp_iterator_new (xmp, NULL, NULL, XMP_ITER_JUSTCHILDREN); |
| |
| if (NULL == xmp_iter) |
| goto done; |
| |
| while (xmp_iterator_next (xmp_iter, xstr_schema, xstr_path, xstr_prop, &opt)) { |
| const char *schema = xmp_string_cstr (xstr_schema); |
| const char *path = xmp_string_cstr (xstr_path); |
| |
| if (XMP_IS_NODE_SCHEMA (opt)) { |
| GST_LOG ("%s", schema); |
| metadataparse_xmp_iter_node_schema (taglist, mode, xmp, schema, path); |
| } else { |
| GST_LOG ("Unexpected iteraction"); |
| } |
| } |
| |
| done: |
| |
| if (xmp_iter) |
| xmp_iterator_free (xmp_iter); |
| |
| if (xstr_prop) |
| xmp_string_free (xstr_prop); |
| |
| if (xstr_path) |
| xmp_string_free (xstr_path); |
| |
| if (xstr_schema) |
| xmp_string_free (xstr_schema); |
| } |
| |
| /* |
| * metadataparse_xmp_iter_node_schema: |
| * @taglist: tag list in which extracted tags will be added |
| * @mode: tag list merge mode |
| * @xmp: handle to XMP data from lib exempi |
| * @schema: schema name string |
| * @path: schema path |
| * |
| * This function gets a @schema, finds the #SchemaMap (structure |
| * containing @schema description and map with GST tags) to it. And then call |
| * #metadataparse_xmp_iter_array. In the end, the idea is |
| * to add all XMP Schema mapped tags to @taglist by unsing a specified |
| * merge @mode |
| * @see_also: #metadataparse_xmp_iter |
| * #metadataparse_xmp_iter_array |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadataparse_xmp_iter_node_schema (GstTagList * taglist, GstTagMergeMode mode, |
| XmpPtr xmp, const char *schema, const char *path) |
| { |
| const SchemaMap *schema_map = NULL; |
| gint i; |
| |
| for (i = 0; schemas_map[i]; i++) { |
| if (0 == strcmp (schema, schemas_map[i]->schema)) { |
| schema_map = schemas_map[i]; |
| break; |
| } |
| } |
| |
| metadataparse_xmp_iter_array (taglist, mode, xmp, schema, path, schema_map); |
| } |
| |
| /* |
| * metadataparse_xmp_iter_array: |
| * @taglist: tag list in which extracted tags will be added |
| * @mode: tag list merge mode |
| * @xmp: handle to XMP data from lib exempi |
| * @schema: schema name string |
| * @path: schema path |
| * @schema_map: structure containing @schema description and map with GST tags |
| * |
| * This function looks all the tags into a @schema and call other functions in |
| * order to add the mapped ones to @taglist by using a specified merge @mode |
| * @see_also: #metadataparse_xmp_iter_node_schema |
| * #metadataparse_xmp_iter_simple_qual metadataparse_xmp_iter_simple |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadataparse_xmp_iter_array (GstTagList * taglist, GstTagMergeMode mode, |
| XmpPtr xmp, const char *schema, const char *path, |
| const SchemaMap * schema_map) |
| { |
| XmpStringPtr xstr_schema = xmp_string_new (); |
| XmpStringPtr xstr_path = xmp_string_new (); |
| XmpStringPtr xstr_prop = xmp_string_new (); |
| uint32_t opt = 0; |
| XmpIteratorPtr xmp_iter = NULL; |
| |
| xmp_iter = xmp_iterator_new (xmp, schema, path, XMP_ITER_JUSTCHILDREN); |
| |
| if (NULL == xmp_iter) |
| goto done; |
| |
| while (xmp_iterator_next (xmp_iter, xstr_schema, xstr_path, xstr_prop, &opt)) { |
| const char *schema = xmp_string_cstr (xstr_schema); |
| const char *path = xmp_string_cstr (xstr_path); |
| const char *value = xmp_string_cstr (xstr_prop); |
| |
| if (XMP_IS_NODE_SCHEMA (opt)) { |
| GST_LOG ("Unexpected iteraction"); |
| } else if (XMP_IS_PROP_SIMPLE (opt)) { |
| if (strcmp (path, "") != 0) { |
| if (XMP_HAS_PROP_QUALIFIERS (opt)) { |
| /* ignore language qualifier, just get the first */ |
| metadataparse_xmp_iter_simple_qual (taglist, mode, path, value, |
| schema_map); |
| } else { |
| metadataparse_xmp_iter_simple (taglist, mode, path, value, |
| schema_map); |
| } |
| } |
| } else if (XMP_IS_PROP_ARRAY (opt)) { |
| /* FIXME: array with merge mode */ |
| GstTagMergeMode new_mode = mode; |
| |
| #if 0 |
| //const gchar *tag = ; |
| if (mode == GST_TAG_MERGE_REPLACE) { |
| //gst_tag_list_remove_tag(taglist, ); |
| } |
| #endif |
| if (XMP_IS_ARRAY_ALTTEXT (opt)) { |
| metadataparse_xmp_iter_array (taglist, new_mode, xmp, schema, path, |
| schema_map); |
| xmp_iterator_skip (xmp_iter, XMP_ITER_SKIPSUBTREE); |
| } else { |
| metadataparse_xmp_iter_array (taglist, new_mode, xmp, schema, path, |
| schema_map); |
| xmp_iterator_skip (xmp_iter, XMP_ITER_SKIPSUBTREE); |
| } |
| } |
| |
| } |
| |
| done: |
| |
| if (xmp_iter) |
| xmp_iterator_free (xmp_iter); |
| |
| if (xstr_prop) |
| xmp_string_free (xstr_prop); |
| |
| if (xstr_path) |
| xmp_string_free (xstr_path); |
| |
| if (xstr_schema) |
| xmp_string_free (xstr_schema); |
| |
| } |
| |
| /* |
| * metadataparse_xmp_iter_simple_qual: |
| * @taglist: tag list in which extracted tags will be added |
| * @mode: tag list merge mode |
| * @path: schema path |
| * @value: value of the (@path) tag |
| * @schema_map: structure containing @schema description and map with GST tags |
| * |
| * This function gets a XMP tag (@path) with quilifiers and try to add it |
| * to @taglist by calling #metadataparse_xmp_iter_add_to_tag_list |
| * @see_also: #metadataparse_xmp_iter_array |
| * #metadataparse_xmp_iter_simple #metadataparse_xmp_iter_add_to_tag_list |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadataparse_xmp_iter_simple_qual (GstTagList * taglist, GstTagMergeMode mode, |
| const char *path, const char *value, const SchemaMap * schema_map) |
| { |
| GString *string = g_string_new (path); |
| |
| #ifndef GST_DISABLE_GST_DEBUG |
| gchar *ch; |
| |
| /* remove the language qualifier */ |
| ch = string->str + string->len - 3; |
| while (ch != string->str + schema_map->prefix_len) { |
| if (*ch == '[') { |
| *ch = '\0'; |
| } |
| --ch; |
| } |
| GST_LOG (" %s = %s", string->str, value); |
| #endif /* #ifndef GST_DISABLE_GST_DEBUG */ |
| |
| metadataparse_xmp_iter_add_to_tag_list (taglist, mode, path, value, |
| schema_map, XMP_PROP_HAS_QUALIFIERS); |
| |
| g_string_free (string, TRUE); |
| } |
| |
| /* |
| * metadataparse_xmp_iter_simple: |
| * @taglist: tag list in which extracted tags will be added |
| * @mode: tag list merge mode |
| * @path: schema path |
| * @value: value of the (@path) tag |
| * @schema_map: structure containing @schema description and map with GST tags |
| * |
| * This function gets a simple XMP tag (@path) and try to add it to @taglist by |
| * calling # metadataparse_xmp_iter_add_to_tag_list |
| * @see_also: #metadataparse_xmp_iter_array |
| * #metadataparse_xmp_iter_simple_qual #metadataparse_xmp_iter_add_to_tag_list |
| * |
| * Returns: nothing |
| */ |
| |
| void |
| metadataparse_xmp_iter_simple (GstTagList * taglist, GstTagMergeMode mode, |
| const char *path, const char *value, const SchemaMap * schema_map) |
| { |
| GST_LOG (" %s = %s", path, value); |
| |
| metadataparse_xmp_iter_add_to_tag_list (taglist, mode, path, value, |
| schema_map, 0); |
| |
| } |
| |
| /* |
| * metadataparse_xmp_iter_add_to_tag_list: |
| * @taglist: tag list in which extracted tags will be added |
| * @mode: tag list merge mode |
| * @path: schema path |
| * @value: value of the (@path) tag |
| * @schema_map: structure containing @schema description and map with GST tags |
| * @opt: indicates if the string (@path) has extras caracters like '[' and ']' |
| * |
| * This function gets a XMP tag (@path) and see if it is mapped to a GST tag by |
| * calling #metadataparse_xmp_get_tagsmap_from_path, if so, add it to @taglist |
| * by using a specified merge @mode |
| * @see_also: #metadataparse_xmp_iter_simple_qual |
| * #metadataparse_xmp_iter_simple #metadataparse_xmp_get_tagsmap_from_path |
| * |
| * Returns: nothing |
| */ |
| |
| static void |
| metadataparse_xmp_iter_add_to_tag_list (GstTagList * taglist, |
| GstTagMergeMode mode, const char *path, const char *value, |
| const SchemaMap * schema_map, const uint32_t opt) |
| { |
| GType type; |
| const SchemaTagMap *smaptag = |
| metadataparse_xmp_get_tagsmap_from_path (schema_map, path, opt); |
| |
| if (NULL == smaptag) |
| goto done; |
| |
| if (NULL == smaptag->gst_tag) |
| goto done; |
| |
| type = gst_tag_get_type (smaptag->gst_tag); |
| |
| switch (type) { |
| case G_TYPE_STRING: |
| gst_tag_list_add (taglist, mode, smaptag->gst_tag, value, NULL); |
| break; |
| default: |
| break; |
| } |
| |
| done: |
| |
| return; |
| |
| } |
| |
| /* |
| * metadatamux_xmp_for_each_tag_in_list: |
| * @list: GStreamer tag list from which @tag belongs to |
| * @tag: GStreamer tag to be added to the XMP chunk |
| * @user_data: pointer to #XmpPtr in which the tag will be added |
| * |
| * This function designed to be called for each tag in GST tag list. This |
| * function adds get the tag value from tag @list and then add it to the XMP |
| * chunk by using #XmpPtr and related functions from lib exempi |
| * @see_also: #metadatamux_xmp_create_chunk_from_tag_list |
| * |
| * Returns: nothing |
| */ |
| |
| static void |
| metadatamux_xmp_for_each_tag_in_list (const GstTagList * list, |
| const gchar * tag, gpointer user_data) |
| { |
| XmpPtr xmp = (XmpPtr) user_data; |
| int i; |
| |
| GST_DEBUG ("trying to map tag '%s' to xmp", tag); |
| |
| for (i = 0; schemas_map[i]; i++) { |
| |
| /* FIXME: should try to get all of values (index) for the tag */ |
| |
| const SchemaMap *smap = schemas_map[i]; |
| const SchemaTagMap *stagmap = |
| metadatamux_xmp_get_tagsmap_from_gsttag (smap, tag); |
| |
| if (stagmap) { |
| gchar *value = NULL; |
| GType type = gst_tag_get_type (tag); |
| |
| switch (type) { |
| case G_TYPE_STRING: |
| gst_tag_list_get_string (list, tag, &value); |
| break; |
| default: |
| break; |
| } |
| |
| GST_DEBUG ("found mapping for tag '%s' in schema %s", tag, |
| schemas_map[i]->prefix); |
| |
| if (value) { |
| uint32_t options = 0; |
| |
| #ifdef XMP_1_99_5 |
| if (xmp_get_property (xmp, smap->schema, stagmap->xmp_tag, |
| NULL, &options)) { |
| #else |
| if (xmp_get_property_and_bits (xmp, smap->schema, stagmap->xmp_tag, |
| NULL, &options)) { |
| #endif |
| if (XMP_IS_PROP_SIMPLE (options)) { |
| #ifdef XMP_1_99_5 |
| xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value, 0); |
| #else |
| xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value); |
| #endif |
| } else { |
| xmp_set_array_item (xmp, smap->schema, stagmap->xmp_tag, 1, |
| value, 0); |
| } |
| } else { |
| #ifdef XMP_1_99_5 |
| xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value, 0); |
| #else |
| xmp_set_property (xmp, smap->schema, stagmap->xmp_tag, value); |
| #endif |
| } |
| |
| g_free (value); |
| } |
| } else { |
| GST_DEBUG ("no xmp mapping for tag '%s' in schema %s found", tag, |
| schemas_map[i]->prefix); |
| } |
| } |
| } |
| |
| #endif /* else (ifndef HAVE_XMP) */ |