mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 07:47:17 +00:00
tag: xmp: Add Elevation tag mapping
Adds a mapping to the _ELEVATION tag, this is a different mapping as it has to be mapped into exif:GPSAltitude and exif:GPSAltitudeRef at the same time. So we needed to refactor a little more to be able to deserialize it properly. Now, when parsing a xmp buffer into a taglist all tags are added to a list before being parsed so that when one of the altitude tags are found the deserialization function can search for its complementary tag to do the correct parsing Fixes #613690
This commit is contained in:
parent
e207463582
commit
007bf4fe7c
2 changed files with 179 additions and 21 deletions
|
@ -43,7 +43,8 @@
|
|||
|
||||
typedef gchar *(*XmpSerializationFunc) (const GValue * value);
|
||||
typedef void (*XmpDeserializationFunc) (GstTagList * taglist,
|
||||
const gchar * gst_tag, const gchar * str);
|
||||
const gchar * gst_tag, const gchar * xmp_tag,
|
||||
const gchar * str, GSList ** pending_tags);
|
||||
|
||||
struct _XmpTag
|
||||
{
|
||||
|
@ -84,18 +85,29 @@ static GMutex *__xmp_tag_map_mutex;
|
|||
#define XMP_TAG_MAP_LOCK g_mutex_lock (__xmp_tag_map_mutex)
|
||||
#define XMP_TAG_MAP_UNLOCK g_mutex_unlock (__xmp_tag_map_mutex)
|
||||
|
||||
static void
|
||||
_xmp_tag_add_mapping (const gchar * gst_tag, GPtrArray * array)
|
||||
{
|
||||
GQuark key;
|
||||
GSList *list = NULL;
|
||||
|
||||
key = g_quark_from_string (gst_tag);
|
||||
|
||||
XMP_TAG_MAP_LOCK;
|
||||
list = g_hash_table_lookup (__xmp_tag_map, GUINT_TO_POINTER (key));
|
||||
list = g_slist_append (list, (gpointer) array);
|
||||
g_hash_table_insert (__xmp_tag_map, GUINT_TO_POINTER (key), list);
|
||||
XMP_TAG_MAP_UNLOCK;
|
||||
}
|
||||
|
||||
static void
|
||||
_xmp_tag_add_simple_mapping (const gchar * gst_tag, const gchar * xmp_tag,
|
||||
XmpSerializationFunc serialization_func,
|
||||
XmpDeserializationFunc deserialization_func)
|
||||
{
|
||||
GQuark key;
|
||||
GSList *list = NULL;
|
||||
XmpTag *xmpinfo;
|
||||
GPtrArray *array;
|
||||
|
||||
key = g_quark_from_string (gst_tag);
|
||||
|
||||
xmpinfo = g_slice_new (XmpTag);
|
||||
xmpinfo->tag_name = xmp_tag;
|
||||
xmpinfo->serialize = serialization_func;
|
||||
|
@ -104,11 +116,7 @@ _xmp_tag_add_simple_mapping (const gchar * gst_tag, const gchar * xmp_tag,
|
|||
array = g_ptr_array_sized_new (1);
|
||||
g_ptr_array_add (array, xmpinfo);
|
||||
|
||||
XMP_TAG_MAP_LOCK;
|
||||
list = g_hash_table_lookup (__xmp_tag_map, GUINT_TO_POINTER (key));
|
||||
list = g_slist_append (list, (gpointer) array);
|
||||
g_hash_table_insert (__xmp_tag_map, GUINT_TO_POINTER (key), list);
|
||||
XMP_TAG_MAP_UNLOCK;
|
||||
_xmp_tag_add_mapping (gst_tag, array);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -137,6 +145,7 @@ _xmp_tag_get_mapping_reverse (const gchar * xmp_tag, XmpTag ** _xmp_tag)
|
|||
gpointer key, value;
|
||||
const gchar *ret = NULL;
|
||||
GSList *walk;
|
||||
gint index;
|
||||
|
||||
XMP_TAG_MAP_LOCK;
|
||||
g_hash_table_iter_init (&iter, __xmp_tag_map);
|
||||
|
@ -145,14 +154,20 @@ _xmp_tag_get_mapping_reverse (const gchar * xmp_tag, XmpTag ** _xmp_tag)
|
|||
|
||||
for (walk = list; walk; walk = g_slist_next (walk)) {
|
||||
GPtrArray *array = (GPtrArray *) walk->data;
|
||||
XmpTag *xmpinfo = (XmpTag *) g_ptr_array_index (array, 0);
|
||||
if (strcmp (xmpinfo->tag_name, xmp_tag) == 0) {
|
||||
*_xmp_tag = xmpinfo;
|
||||
ret = g_quark_to_string (GPOINTER_TO_UINT (key));
|
||||
break;
|
||||
|
||||
for (index = 0; index < array->len; index++) {
|
||||
XmpTag *xmpinfo = (XmpTag *) g_ptr_array_index (array, index);
|
||||
|
||||
if (strcmp (xmpinfo->tag_name, xmp_tag) == 0) {
|
||||
*_xmp_tag = xmpinfo;
|
||||
ret = g_quark_to_string (GPOINTER_TO_UINT (key));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
XMP_TAG_MAP_UNLOCK;
|
||||
return ret;
|
||||
}
|
||||
|
@ -269,24 +284,133 @@ error:
|
|||
|
||||
static void
|
||||
deserialize_exif_latitude (GstTagList * taglist, const gchar * gst_tag,
|
||||
const gchar * str)
|
||||
const gchar * xmp_tag, const gchar * str, GSList ** pending_tags)
|
||||
{
|
||||
deserialize_exif_gps_coordinate (taglist, gst_tag, str, 'N', 'S');
|
||||
}
|
||||
|
||||
static void
|
||||
deserialize_exif_longitude (GstTagList * taglist, const gchar * gst_tag,
|
||||
const gchar * str)
|
||||
const gchar * xmp_tag, const gchar * str, GSList ** pending_tags)
|
||||
{
|
||||
deserialize_exif_gps_coordinate (taglist, gst_tag, str, 'E', 'W');
|
||||
}
|
||||
|
||||
static gchar *
|
||||
serialize_exif_altitude (const GValue * value)
|
||||
{
|
||||
gdouble num;
|
||||
gint frac_n;
|
||||
gint frac_d;
|
||||
|
||||
num = g_value_get_double (value);
|
||||
|
||||
if (num < 0)
|
||||
num *= -1;
|
||||
|
||||
gst_util_double_to_fraction (num, &frac_n, &frac_d);
|
||||
|
||||
return g_strdup_printf ("%d/%d", frac_n, frac_d);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
serialize_exif_altituderef (const GValue * value)
|
||||
{
|
||||
gdouble num;
|
||||
|
||||
num = g_value_get_double (value);
|
||||
|
||||
if (num >= 0)
|
||||
return g_strdup ("0");
|
||||
return g_strdup ("1");
|
||||
}
|
||||
|
||||
static void
|
||||
deserialize_exif_altitude (GstTagList * taglist, const gchar * gst_tag,
|
||||
const gchar * xmp_tag, const gchar * str, GSList ** pending_tags)
|
||||
{
|
||||
const gchar *altitude_str = NULL;
|
||||
const gchar *altituderef_str = NULL;
|
||||
gint frac_n;
|
||||
gint frac_d;
|
||||
gdouble value;
|
||||
|
||||
GSList *entry;
|
||||
PendingXmpTag *ptag = NULL;
|
||||
|
||||
/* find the other missing part */
|
||||
if (strcmp (xmp_tag, "exif:GPSAltitude") == 0) {
|
||||
altitude_str = str;
|
||||
|
||||
for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
|
||||
ptag = (PendingXmpTag *) entry->data;
|
||||
|
||||
if (strcmp (ptag->xmp_tag->tag_name, "exif:GPSAltitudeRef") == 0) {
|
||||
altituderef_str = ptag->str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (strcmp (xmp_tag, "exif:GPSAltitudeRef") == 0) {
|
||||
altituderef_str = str;
|
||||
|
||||
for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
|
||||
ptag = (PendingXmpTag *) entry->data;
|
||||
|
||||
if (strcmp (ptag->xmp_tag->tag_name, "exif:GPSAltitude") == 0) {
|
||||
altitude_str = ptag->str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
GST_WARNING ("Unexpected xmp tag %s", xmp_tag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!altitude_str) {
|
||||
GST_WARNING ("Missing exif:GPSAltitude tag");
|
||||
return;
|
||||
}
|
||||
if (!altituderef_str) {
|
||||
GST_WARNING ("Missing exif:GPSAltitudeRef tag");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sscanf (altitude_str, "%d/%d", &frac_n, &frac_d) != 2) {
|
||||
GST_WARNING ("Failed to parse fraction: %s", altitude_str);
|
||||
return;
|
||||
}
|
||||
|
||||
gst_util_fraction_to_double (frac_n, frac_d, &value);
|
||||
|
||||
if (altituderef_str[0] == '0') {
|
||||
} else if (altituderef_str[0] == '1') {
|
||||
value *= -1;
|
||||
} else {
|
||||
GST_WARNING ("Unexpected exif:AltitudeRef value: %s", altituderef_str);
|
||||
return;
|
||||
}
|
||||
|
||||
/* add to the taglist */
|
||||
gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
|
||||
GST_TAG_GEO_LOCATION_ELEVATION, value, NULL);
|
||||
|
||||
/* clean up entry */
|
||||
g_free (ptag->str);
|
||||
g_slice_free (PendingXmpTag, ptag);
|
||||
*pending_tags = g_slist_delete_link (*pending_tags, entry);
|
||||
}
|
||||
|
||||
/* look at this page for addtional schemas
|
||||
* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/XMP.html
|
||||
*/
|
||||
static gpointer
|
||||
_init_xmp_tag_map ()
|
||||
{
|
||||
GPtrArray *array;
|
||||
XmpTag *xmpinfo;
|
||||
|
||||
__xmp_tag_map_mutex = g_mutex_new ();
|
||||
__xmp_tag_map = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
|
@ -313,6 +437,20 @@ _init_xmp_tag_map ()
|
|||
"exif:GPSLongitude", serialize_exif_longitude,
|
||||
deserialize_exif_longitude);
|
||||
|
||||
/* compound tag */
|
||||
array = g_ptr_array_sized_new (2);
|
||||
xmpinfo = g_slice_new (XmpTag);
|
||||
xmpinfo->tag_name = "exif:GPSAltitude";
|
||||
xmpinfo->serialize = serialize_exif_altitude;
|
||||
xmpinfo->deserialize = deserialize_exif_altitude;
|
||||
g_ptr_array_add (array, xmpinfo);
|
||||
xmpinfo = g_slice_new (XmpTag);
|
||||
xmpinfo->tag_name = "exif:GPSAltitudeRef";
|
||||
xmpinfo->serialize = serialize_exif_altituderef;
|
||||
xmpinfo->deserialize = deserialize_exif_altitude;
|
||||
g_ptr_array_add (array, xmpinfo);
|
||||
_xmp_tag_add_mapping (GST_TAG_GEO_LOCATION_ELEVATION, array);
|
||||
|
||||
/* photoshop schema */
|
||||
_xmp_tag_add_simple_mapping (GST_TAG_GEO_LOCATION_COUNTRY,
|
||||
"photoshop:Country", NULL, NULL);
|
||||
|
@ -370,12 +508,12 @@ static GstXmpNamespaceMap ns_map[] = {
|
|||
|
||||
static void
|
||||
read_one_tag (GstTagList * list, const gchar * tag, XmpTag * xmptag,
|
||||
const gchar * v)
|
||||
const gchar * v, GSList ** pending_tags)
|
||||
{
|
||||
GType tag_type;
|
||||
|
||||
if (xmptag && xmptag->deserialize) {
|
||||
xmptag->deserialize (list, tag, v);
|
||||
xmptag->deserialize (list, tag, xmptag->tag_name, v, pending_tags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -639,11 +777,12 @@ gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
|
|||
}
|
||||
}
|
||||
|
||||
/* parse the entries */
|
||||
while (pending_tags) {
|
||||
PendingXmpTag *ptag = (PendingXmpTag *) pending_tags->data;
|
||||
|
||||
read_one_tag (list, ptag->gst_tag, ptag->xmp_tag, ptag->str);
|
||||
pending_tags = g_slist_delete_link (pending_tags, pending_tags);
|
||||
|
||||
read_one_tag (list, ptag->gst_tag, ptag->xmp_tag, ptag->str, &pending_tags);
|
||||
|
||||
g_free (ptag->str);
|
||||
g_slice_free (PendingXmpTag, ptag);
|
||||
|
|
|
@ -898,6 +898,12 @@ do_xmp_tag_serialization_deserialization (const gchar * gsttag, GValue * value)
|
|||
g_free (vs);
|
||||
g_free (vr);
|
||||
}
|
||||
if (strcmp (name_sent, GST_TAG_GEO_LOCATION_ELEVATION) == 0) {
|
||||
gdouble a, b;
|
||||
a = g_value_get_double (value_sent);
|
||||
b = g_value_get_double (value_recv);
|
||||
GST_WARNING ("A=%lf B=%lf", a, b);
|
||||
}
|
||||
fail_unless (comparison == GST_VALUE_EQUAL,
|
||||
"tag item %s has been received with different type or value",
|
||||
name_sent);
|
||||
|
@ -950,6 +956,19 @@ GST_START_TEST (test_xmp_tags_serialization_deserialization)
|
|||
&value);
|
||||
do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_LONGITUDE,
|
||||
&value);
|
||||
|
||||
g_value_set_double (&value, 0);
|
||||
do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_ELEVATION,
|
||||
&value);
|
||||
g_value_set_double (&value, 100);
|
||||
do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_ELEVATION,
|
||||
&value);
|
||||
g_value_set_double (&value, 500.25);
|
||||
do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_ELEVATION,
|
||||
&value);
|
||||
g_value_set_double (&value, -12.75);
|
||||
do_xmp_tag_serialization_deserialization (GST_TAG_GEO_LOCATION_ELEVATION,
|
||||
&value);
|
||||
g_value_unset (&value);
|
||||
|
||||
g_value_init (&value, GST_TYPE_DATE);
|
||||
|
|
Loading…
Reference in a new issue