diff --git a/ChangeLog b/ChangeLog index f273020e0b..3f44ff49c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2008-10-06 Stefan Kost + + * configure.ac + * ext/metadata/README: + * ext/metadata/metadataexif.c: + * ext/metadata/metadatatags.c: + * ext/metadata/metadatatags.h: + Start using core geo tags (bump req). Fix handling of location + references. + + * tests/check/Makefile.am: + Sort blacklisted elements and remove moved ones. Add new test. + + * tests/check/pipelines/metadata.c: + Add first tests for metadata element. + + * tests/icles/metadata_editor.c: + Move free to correct place. + 2008-10-06 Stefan Kost * tests/check/generic/states.c: diff --git a/configure.ac b/configure.ac index 414a962ecd..08752f0365 100644 --- a/configure.ac +++ b/configure.ac @@ -45,7 +45,7 @@ AC_LIBTOOL_WIN32_DLL AM_PROG_LIBTOOL dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.20 +GST_REQ=0.10.21 GSTPB_REQ=0.10.20 dnl *** autotools stuff **** diff --git a/ext/metadata/README b/ext/metadata/README index f3cd20d7ec..8afd33c7b8 100644 --- a/ext/metadata/README +++ b/ext/metadata/README @@ -87,3 +87,20 @@ Obs: By looking at the proposed design (1- view and 2- modify) seems that the me application could send width and height tag events to the pipeline * should metadatamux get info from caps (width and height) and use if not receive a event with such tags? + +Testing +GST_DEBUG="*:2,metadata*:4" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_ppp.jpeg" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_ppn.jpeg" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_pnp.jpeg" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_pnn.jpeg" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_npp.jpeg" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_npn.jpeg" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3" ! metadatamux ! filesink location="meta_test_nnp.jpeg" +gst-launch videotestsrc num-buffers=1 ! jpegenc ! taginject tags="geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3" ! metadatamux ! filesink location="meta_test_nnn.jpeg" + +exiv2 -pt pr meta_test_ppp.jpeg | grep "Exif.GPSInfo" +exif meta_test_ppp.jpeg + +gst-launch -t filesrc location="meta_test_ppp.jpeg" ! metadatademux ! fakesink + diff --git a/ext/metadata/metadataexif.c b/ext/metadata/metadataexif.c index 89c4e2b0e8..6924511d8d 100644 --- a/ext/metadata/metadataexif.c +++ b/ext/metadata/metadataexif.c @@ -241,13 +241,13 @@ static MapIntStr mappedTags[] = { GST_TAG_IMAGE_YRESOLUTION /*GST_TYPE_FRACTION*/}, /* inches */ {EXIF_TAG_GPS_ALTITUDE, /*RATIONAL,*/ EXIF_IFD_GPS, - GST_TAG_GPS_ALTITUDE /*GST_TYPE_FRACTION*/}, + GST_TAG_GEO_LOCATION_ELEVATION /*G_TYPE_DOUBLE*/}, {EXIF_TAG_GPS_LATITUDE, /*RATIONAL(3),*/ EXIF_IFD_GPS, - GST_TAG_GPS_LATITUDE /*G_TYPE_STRING*/}, + GST_TAG_GEO_LOCATION_LATITUDE /*G_TYPE_DOUBLE*/}, {EXIF_TAG_GPS_LONGITUDE, /*RATIONAL(3),*/ EXIF_IFD_GPS, - GST_TAG_GPS_LONGITUDE /*G_TYPE_STRING*/}, + GST_TAG_GEO_LOCATION_LONGITUDE /*G_TYPE_DOUBLE*/}, {0, EXIF_IFD_COUNT, NULL} }; @@ -289,13 +289,6 @@ static gboolean metadataparse_exif_convert_to_datetime (GString * dt); static gboolean metadatamux_exif_convert_from_datetime (GString * dt); -static gboolean -metadatamux_exif_convert_from_gps (guint8 * data, const char *lt, char *ref); - -static gboolean -metadataparse_exif_convert_to_gps (const guint8 * data, GString * lt, - const int exif_tag, const MEUserData * meudata); - /* * extern functions implementations */ @@ -531,7 +524,6 @@ static void metadataparse_exif_content_foreach_entry_func (ExifEntry * entry, void *user_data) { - char buf[2048]; MEUserData *meudata = (MEUserData *) user_data; GType type = G_TYPE_NONE; ExifByteOrder byte_order; @@ -573,14 +565,6 @@ metadataparse_exif_content_foreach_entry_func (ExifEntry * entry, numerator = (gint) v_rat.numerator; denominator = (gint) v_rat.denominator; } - if (meudata->altitude_ref == 1) { - if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { - if (numerator > 0) - numerator = -numerator; - if (denominator < 0) - denominator = -denominator; - } - } if (meudata->resolution_unit == 3) { /* converts from cm to inches */ if (entry->tag == EXIF_TAG_X_RESOLUTION @@ -606,10 +590,10 @@ metadataparse_exif_content_foreach_entry_func (ExifEntry * entry, gst_tag_list_add (meudata->taglist, meudata->mode, tag, buf, NULL); gst_buffer_unref (buf); } else { - switch (type) { case G_TYPE_STRING: { + char buf[2048]; const gchar *str = exif_entry_get_value (entry, buf, sizeof (buf)); GString *value = NULL; @@ -626,17 +610,6 @@ metadataparse_exif_content_foreach_entry_func (ExifEntry * entry, str = NULL; } - } else if (entry->tag == EXIF_TAG_GPS_LATITUDE - || entry->tag == EXIF_TAG_GPS_LONGITUDE) { - value = g_string_new_len (str, 11); - /* 21 is enough memory to hold "DDD:MM:SSk" */ - if (metadataparse_exif_convert_to_gps (entry->data, value, - entry->tag, meudata)) { - str = value->str; - } else { - GST_ERROR ("Unexpected date & time format for %s", tag); - str = NULL; - } } if (str) gst_tag_list_add (meudata->taglist, meudata->mode, tag, str, NULL); @@ -682,28 +655,75 @@ metadataparse_exif_content_foreach_entry_func (ExifEntry * entry, gst_tag_list_add (meudata->taglist, meudata->mode, tag, value, NULL); } break; + case G_TYPE_DOUBLE: + { + gdouble value = 0.0; + + if (entry->tag == EXIF_TAG_GPS_LATITUDE + || entry->tag == EXIF_TAG_GPS_LONGITUDE) { + ExifRational *rt = (ExifRational *) entry->data; + + /* DDD - degrees */ + value = (gdouble) rt->numerator / (gdouble) rt->denominator; + rt++; + + /* MM - minutes and SS - seconds */ + if (rt->numerator % rt->denominator) { + value += (gdouble) rt->numerator / (gdouble) rt->denominator; + } else { + value += rt->numerator / rt->denominator; + rt++; + value += rt->numerator / rt->denominator; + } + + /* apply sign */ + if (entry->tag == EXIF_TAG_GPS_LATITUDE) { + if (((meudata->latitude_ref == 'S') && (value > 0.0)) || + ((meudata->latitude_ref == 'N') && (value < 0.0))) { + value = -value; + } + } else { + if (((meudata->longitude_ref == 'W') && (value > 0.0)) || + ((meudata->longitude_ref == 'E') && (value < 0.0))) { + value = -value; + } + } + GST_DEBUG ("long/lat : %lf", value); + } + if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { + ExifRational v_rat = exif_get_rational (entry->data, byte_order); + value = (gdouble) v_rat.numerator / (gdouble) v_rat.denominator; + if (((meudata->altitude_ref == 1) && (value > 0.0)) || + ((meudata->altitude_ref == 0) && (value < 0.0))) { + value = -value; + } + GST_DEBUG ("altitude = %lf", value); + } + gst_tag_list_add (meudata->taglist, meudata->mode, tag, value, NULL); + } + break; default: break; } - } done: - - GST_LOG ("\n Entry %p: %s (%s)\n" - " Size, Comps: %d, %d\n" - " Value: %s\n" - " Title: %s\n" - " Description: %s\n", - entry, - exif_tag_get_name (entry->tag), - exif_format_get_name (entry->format), - entry->size, - (int) (entry->components), - exif_entry_get_value (entry, buf, sizeof (buf)), - exif_tag_get_title (entry->tag), exif_tag_get_description (entry->tag)); - + { + char buf[2048]; + GST_LOG ("\n Entry %p: %s (%s)\n" + " Size, Comps: %d, %d\n" + " Value: %s\n" + " Title: %s\n" + " Description: %s\n", + entry, + exif_tag_get_name (entry->tag), + exif_format_get_name (entry->format), + entry->size, + (int) (entry->components), + exif_entry_get_value (entry, buf, sizeof (buf)), + exif_tag_get_title (entry->tag), exif_tag_get_description (entry->tag)); + } return; } @@ -754,64 +774,52 @@ metadataparse_handle_unit_tags (ExifEntry * entry, MEUserData * meudata, GST_TAG_IMAGE_YRESOLUTION, value * 0.4f, NULL); } } - break; case EXIF_TAG_GPS_ALTITUDE_REF: { - const GValue *value = gst_tag_list_get_value_index (meudata->taglist, - GST_TAG_GPS_ALTITUDE, 0); + gdouble value; meudata->altitude_ref = entry->data[0]; - - if (value) { - gint n, d; - - n = gst_value_get_fraction_numerator (value); - d = gst_value_get_fraction_denominator (value); - if (meudata->altitude_ref == 1) { /* bellow sea */ - if (IS_FRACT_POSITIVE (n, d)) { /* if n * d > 0 */ - gst_tag_list_add (meudata->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_GPS_ALTITUDE, -n, d, NULL); - } + if (gst_tag_list_get_double (meudata->taglist, + GST_TAG_GEO_LOCATION_ELEVATION, &value)) { + GST_DEBUG ("alt-ref: %d", meudata->altitude_ref); + if (((meudata->altitude_ref == 1) && (value > 0.0)) || + ((meudata->altitude_ref == 0) && (value < 0.0))) { + gst_tag_list_add (meudata->taglist, GST_TAG_MERGE_REPLACE, + GST_TAG_GEO_LOCATION_ELEVATION, -value, NULL); } } } break; case EXIF_TAG_GPS_LATITUDE_REF: { - - gchar *value = NULL; + gdouble value; meudata->latitude_ref = entry->data[0]; - if (gst_tag_list_get_string (meudata->taglist, GST_TAG_GPS_LATITUDE, - &value)) { - GString *str = g_string_new (value); - - if (str->len == 10) { - str->str[9] = meudata->latitude_ref; + if (gst_tag_list_get_double (meudata->taglist, + GST_TAG_GEO_LOCATION_LATITUDE, &value)) { + GST_DEBUG ("lat-ref: %c", meudata->latitude_ref); + if (((meudata->latitude_ref == 'S') && (value > 0.0)) || + ((meudata->latitude_ref == 'N') && (value < 0.0))) { gst_tag_list_add (meudata->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_GPS_LATITUDE, str->str, NULL); + GST_TAG_GEO_LOCATION_LATITUDE, -value, NULL); } - g_string_free (str, TRUE); } - } break; case EXIF_TAG_GPS_LONGITUDE_REF: { - gchar *value = NULL; + gdouble value; meudata->longitude_ref = entry->data[0]; - if (gst_tag_list_get_string (meudata->taglist, GST_TAG_GPS_LONGITUDE, - &value)) { - GString *str = g_string_new (value); - - if (str->len == 10) { - str->str[9] = meudata->longitude_ref; + if (gst_tag_list_get_double (meudata->taglist, + GST_TAG_GEO_LOCATION_LONGITUDE, &value)) { + GST_DEBUG ("lon-ref: %c", meudata->longitude_ref); + if (((meudata->longitude_ref == 'W') && (value > 0.0)) || + ((meudata->longitude_ref == 'E') && (value < 0.0))) { gst_tag_list_add (meudata->taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_GPS_LONGITUDE, str->str, NULL); + GST_TAG_GEO_LOCATION_LONGITUDE, -value, NULL); } - g_string_free (str, TRUE); } } break; @@ -821,7 +829,6 @@ metadataparse_handle_unit_tags (ExifEntry * entry, MEUserData * meudata, } return ret; - } @@ -897,33 +904,6 @@ metadatamux_exif_for_each_tag_in_list (const GstTagList * list, { ExifRational r; - if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { - - ExifEntry *ref_entry = NULL; - - ref_entry = exif_data_get_entry (ed, EXIF_TAG_GPS_ALTITUDE_REF); - if (ref_entry) { - exif_entry_ref (ref_entry); - } else { - ref_entry = exif_entry_new (); - exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); - exif_entry_initialize (ref_entry, EXIF_TAG_GPS_ALTITUDE_REF); - } - if (ref_entry->data == NULL) { - ref_entry->format = EXIF_FORMAT_BYTE; - ref_entry->components = 1; - ref_entry->size = 1; - ref_entry->data = g_malloc (1); - } - /* if n * d > 0 */ - if (IS_FRACT_POSITIVE (numerator, denominator)) { - ref_entry->data[0] = 0; - } else { - ref_entry->data[0] = 1; - } - exif_entry_unref (ref_entry); - - } if (entry->tag == EXIF_TAG_X_RESOLUTION || entry->tag == EXIF_TAG_Y_RESOLUTION) { ExifEntry *unit_entry = NULL; @@ -960,14 +940,12 @@ metadatamux_exif_for_each_tag_in_list (const GstTagList * list, entry->data = g_malloc (entry->size); memcpy (entry->data, GST_BUFFER_DATA (buf), entry->size); } else { - switch (type) { case G_TYPE_STRING: { gchar *value = NULL; if (gst_tag_list_get_string (list, tag, &value)) { - if (entry->tag == EXIF_TAG_DATE_TIME_DIGITIZED || entry->tag == EXIF_TAG_DATE_TIME || entry->tag == EXIF_TAG_DATE_TIME_ORIGINAL) { @@ -981,45 +959,13 @@ metadatamux_exif_for_each_tag_in_list (const GstTagList * list, g_free (value); value = datetime->str; g_string_free (datetime, FALSE); - } else if (entry->tag == EXIF_TAG_GPS_LATITUDE - || entry->tag == EXIF_TAG_GPS_LONGITUDE) { - char ref; - - if (metadatamux_exif_convert_from_gps (entry->data, value, &ref)) { - ExifEntry *ref_entry = NULL; - const ExifTag ref_tag = entry->tag == EXIF_TAG_GPS_LATITUDE ? - EXIF_TAG_GPS_LATITUDE_REF : EXIF_TAG_GPS_LONGITUDE_REF; - - ref_entry = exif_data_get_entry (ed, ref_tag); - if (ref_entry) { - exif_entry_ref (ref_entry); - } else { - ref_entry = exif_entry_new (); - exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); - exif_entry_initialize (ref_entry, ref_tag); - } - if (ref_entry->data == NULL) { - ref_entry->format = EXIF_FORMAT_ASCII; - ref_entry->components = 2; - ref_entry->size = 2; - ref_entry->data = g_malloc (2); - } - ref_entry->data[0] = ref; - ref_entry->data[1] = 0; - exif_entry_unref (ref_entry); - } - /* has already been add and it is not an Exif ASCII type */ - g_free (value); - value = NULL; - } - if (value) { + } else if (value) { entry->components = strlen (value) + 1; entry->size = exif_format_get_size (entry->format) * entry->components; entry->data = (guint8 *) value; value = NULL; } - } } break; @@ -1056,6 +1002,89 @@ metadatamux_exif_for_each_tag_in_list (const GstTagList * list, break; } + } + break; + case G_TYPE_DOUBLE: + { + gdouble value; + + gst_tag_list_get_double (list, tag, &value); + if (entry->tag == EXIF_TAG_GPS_LATITUDE + || entry->tag == EXIF_TAG_GPS_LONGITUDE) { + ExifRational *rt = (ExifRational *) entry->data; + gdouble v = fabs (value); + ExifEntry *ref_entry = NULL; + char ref; + const ExifTag ref_tag = entry->tag == EXIF_TAG_GPS_LATITUDE ? + EXIF_TAG_GPS_LATITUDE_REF : EXIF_TAG_GPS_LONGITUDE_REF; + + rt->numerator = (gulong) v; + rt->denominator = 1; + v -= rt->numerator; + rt++; + + rt->numerator = (gulong) (0.5 + v * 100.0); + rt->denominator = 100; + rt++; + + rt->numerator = 0; + rt->denominator = 1; + + if (entry->tag == EXIF_TAG_GPS_LONGITUDE) { + GST_DEBUG ("longitude : %lf", value); + ref = (value < 0.0) ? 'W' : 'E'; + } else { + GST_DEBUG ("latitude : %lf", value); + ref = (value < 0.0) ? 'S' : 'N'; + } + + ref_entry = exif_data_get_entry (ed, ref_tag); + if (ref_entry) { + exif_entry_ref (ref_entry); + } else { + ref_entry = exif_entry_new (); + exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); + exif_entry_initialize (ref_entry, ref_tag); + } + if (ref_entry->data == NULL) { + ref_entry->format = EXIF_FORMAT_ASCII; + ref_entry->components = 2; + ref_entry->size = 2; + ref_entry->data = g_malloc (2); + } + ref_entry->data[0] = ref; + ref_entry->data[1] = 0; + exif_entry_unref (ref_entry); + } else if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { + ExifEntry *ref_entry = NULL; + ExifRational *rt = (ExifRational *) entry->data; + + rt->numerator = (gulong) fabs (10.0 * value); + rt->denominator = 10; + + GST_DEBUG ("altitude : %lf", value); + + ref_entry = exif_data_get_entry (ed, EXIF_TAG_GPS_ALTITUDE_REF); + if (ref_entry) { + exif_entry_ref (ref_entry); + } else { + ref_entry = exif_entry_new (); + exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); + exif_entry_initialize (ref_entry, EXIF_TAG_GPS_ALTITUDE_REF); + } + if (ref_entry->data == NULL) { + ref_entry->format = EXIF_FORMAT_BYTE; + ref_entry->components = 1; + ref_entry->size = 1; + ref_entry->data = g_malloc (1); + } + if (value > 0.0) { + ref_entry->data[0] = 0; + } else { + ref_entry->data[0] = 1; + } + exif_entry_unref (ref_entry); + } } break; default: @@ -1271,172 +1300,4 @@ done: } -/* - * metadatamux_exif_convert_from_gps: - * @data: pointer to an array of 3 ExifRational in which gps will be stored - * @lt: a string containing the gps coordinate formated as "DDD,MM,SSk" - * or "DDD,MM.mmk" (this is the same as specified in XMP). - * @ref: at the end will store the reference ('N', 'S', 'E', 'W') - * - * This function converts from the format "DDD,MM,SSk" or "DDD,MM.mmk" - * (the same as specified in XMP) into Exif coordinates. - * D- degrees, M- minutes, S- seconds, k- 'N', 'S', 'E', 'W' - * (North, South, East, West) - * - * Returns: - * - * %TRUE if converted sucessfull - * - * %FALSE if @lt is bad formated - * - * - */ - -static gboolean -metadatamux_exif_convert_from_gps (guint8 * data, const char *lt, char *ref) -{ - /* "DDD,MM,SSk" or "DDD,MM.mmk" */ - /* 0123456789 0123456789 */ - gboolean ret = TRUE; - char *p = (char *) lt; - ExifRational *rt = (ExifRational *) data; - - if (strlen (lt) != 10) - goto error; - - if (lt[6] == ',' || lt[6] == '.') { - if (IS_NUMBER (*p) && IS_NUMBER (*(p + 1)) && IS_NUMBER (*(p + 2))) { - rt->numerator = CHAR_TO_INT (*p) * 100; - p++; - rt->numerator += CHAR_TO_INT (*p) * 10; - p++; - rt->numerator += CHAR_TO_INT (*p); - p++; - rt->denominator = 1; - } else { - goto error; - } - p++; - rt++; - if (IS_NUMBER (*p) && IS_NUMBER (*(p + 1))) { - rt->numerator = CHAR_TO_INT (*p) * 10; - p++; - rt->numerator += CHAR_TO_INT (*p); - p++; - rt->denominator = 1; - } else { - goto error; - } - p++; - rt++; - if (IS_NUMBER (*p) && IS_NUMBER (*(p + 1))) { - rt->numerator = CHAR_TO_INT (*p) * 10; - p++; - rt->numerator += CHAR_TO_INT (*p); - p++; - rt->denominator = 1; - } else { - goto error; - } - } else { - goto error; - } - - if (lt[9] != 'N' && lt[9] != 'S' && lt[9] != 'E' && lt[9] != 'W') - goto error; - - *ref = lt[9]; - - goto done; -error: - - ret = FALSE; - -done: - - return ret; - -} - -/* - * metadatamux_exif_convert_from_gps: - * @data: pointer to an array of 3 ExifRational from which gps will be read - * @lt: at the end this will have the gps coordinate formated as "DDD,MM,SSk" - * or "DDD,MM.mmk" (this is the same as specified in XMP). - * @exif_tag: EXIF_TAG_GPS_LATITUDE or EXIF_TAG_GPS_LONGITUDE - * @meudata: at the end will store the reference ('N', 'S', 'E', 'W') - * in @meudata->latitude_ref or meudata->longitude_ref depending on @exif_tag - * - * This function converts from Exif coordinates to the format "DDD,MM,SSk" - * or "DDD,MM.mmk" (the same as specified in XMP). - * D- degrees, M- minutes, S- seconds, k- 'N', 'S', 'E', 'W' - * (North, South, East, West) - * Precondition: @lt->allocated_len must be at least 11. - * - * Returns: - * - * %TRUE if converted sucessfull - * - * %FALSE if error - * - * - */ - -static gboolean -metadataparse_exif_convert_to_gps (const guint8 * data, GString * lt, - const int exif_tag, const MEUserData * meudata) -{ - ExifRational *rt = (ExifRational *) data; - char *str = lt->str; - gboolean ret = TRUE; - char ref; - - if (lt->allocated_len < 11) - goto error; - - if (exif_tag == EXIF_TAG_GPS_LATITUDE) - ref = meudata->latitude_ref; - else if (exif_tag == EXIF_TAG_GPS_LONGITUDE) - ref = meudata->longitude_ref; - else - goto error; - - /* DDD - degrees */ - - sprintf (str, "%03u,", rt->numerator / rt->denominator); - rt++; - str += 4; - - /* MM - minutes and SS - seconds */ - - if (rt->numerator % rt->denominator) { - sprintf (str, "%05.02f", (float) rt->numerator / (float) rt->denominator); - str += 5; - *str++ = ref; - *str = '\0'; - } else { - sprintf (str, "%02u,", rt->numerator / rt->denominator); - str += 3; - rt++; - sprintf (str, "%02u", rt->numerator / rt->denominator); - str += 2; - *str++ = ref; - *str = '\0'; - } - - /* if here, everything is ok */ - goto done; -error: - - ret = FALSE; - -done: - - /* FIXME: do we need to check if the date is valid ? */ - - if (ret) - lt->len = 10; - return ret; -} - #endif /* else (ifndef HAVE_EXIF) */ diff --git a/ext/metadata/metadatatags.c b/ext/metadata/metadatatags.c index b79830d1f1..82e6c381e3 100644 --- a/ext/metadata/metadatatags.c +++ b/ext/metadata/metadatatags.c @@ -427,35 +427,6 @@ metadata_tags_exif_register (void) gst_tag_register (GST_TAG_IMAGE_YRESOLUTION, GST_TAG_FLAG_META, GST_TYPE_FRACTION, GST_TAG_IMAGE_YRESOLUTION, "Vertical resolution in pixels per inch", NULL); - - /* GPS tags */ - - /* Altitude: - * positive values means above the sea level - * negative values means under the sea level - */ - - gst_tag_register (GST_TAG_GPS_ALTITUDE, GST_TAG_FLAG_META, - GST_TYPE_FRACTION, GST_TAG_GPS_ALTITUDE, "Altitude", NULL); - - /* Latitude: - * "DDD,MM,SSk" or "DDD,MM.mmk" fixed size string where: - * D- degrees, M- minutes, S-seconds, - * mm- fraction of minutes, k- N (north) or S (south) - */ - - gst_tag_register (GST_TAG_GPS_LATITUDE, GST_TAG_FLAG_META, - G_TYPE_STRING, GST_TAG_GPS_LATITUDE, "Latitude", NULL); - - /* Longitude: - * "DDD,MM,SSk" or "DDD,MM.mmk" fixed size string where: - * D- degrees, M- minutes, S-seconds, - * mm- fraction of minutes, k- N (north) or S (south) - */ - - gst_tag_register (GST_TAG_GPS_LONGITUDE, GST_TAG_FLAG_META, - G_TYPE_STRING, GST_TAG_GPS_LONGITUDE, "Longitude", NULL); - } /* diff --git a/ext/metadata/metadatatags.h b/ext/metadata/metadatatags.h index 004a17c247..8500f15aa7 100644 --- a/ext/metadata/metadatatags.h +++ b/ext/metadata/metadatatags.h @@ -116,13 +116,10 @@ typedef enum { #define GST_TAG_IMAGE_XRESOLUTION "image-xresolution" #define GST_TAG_IMAGE_YRESOLUTION "image-yresolution" -#define GST_TAG_GPS_ALTITUDE "gps-altitude" #define GST_TAG_GPS_AREA_INFORMATION "" #define GST_TAG_GPS_DIFFERENTIAL "" #define GST_TAG_GPS_DOP "" #define GST_TAG_GPS_IMAGE_DIRECTION "" -#define GST_TAG_GPS_LATITUDE "gps-latitude" -#define GST_TAG_GPS_LONGITUDE "gps-longitude" #define GST_TAG_GPS_MEASURE_MODE "" #define GST_TAG_GPS_PROCESSING_METHOD "" #define GST_TAG_GPS_SATELLITES "" diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index eddeff20fb..f504c5df60 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -13,7 +13,7 @@ TESTS_ENVIRONMENT = \ $(REGISTRY_ENVIRONMENT) \ GST_PLUGIN_SYSTEM_PATH= \ GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(GSTPB_PLUGINS_DIR):$(GST_PLUGINS_DIR) \ - STATE_IGNORE_ELEMENTS="cdaudio festival vcdsrc nassink glimagesink dvbsrc dvbbasebin sdlaudiosink sdlvideosink alsaspdifsink dfbvideosink dc1394src" + STATE_IGNORE_ELEMENTS="alsaspdifsink cdaudio dc1394src dvbsrc dvbbasebin dfbvideosink festival nassink sdlaudiosink sdlvideosink vcdsrc" plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ @@ -27,6 +27,12 @@ SUPPRESSIONS = $(top_srcdir)/common/gst.supp $(srcdir)/gst-plugins-bad.supp clean-local: clean-local-check +if USE_METADATA +check_metadata = pipelines/metadata +else +check_metadata = +endif + if USE_MPEG2ENC check_mpeg2enc = elements/mpeg2enc else @@ -82,7 +88,10 @@ check_PROGRAMS = \ $(check_timidity) \ $(check_x264enc) \ elements/selector \ - elements/y4menc + elements/y4menc \ + elements/amrparse \ + elements/aacparse \ + $(check_metadata) noinst_HEADERS = diff --git a/tests/check/pipelines/metadata.c b/tests/check/pipelines/metadata.c new file mode 100644 index 0000000000..c12823fbee --- /dev/null +++ b/tests/check/pipelines/metadata.c @@ -0,0 +1,242 @@ +/* GStreamer + * Copyright (C) 2008 Nokia Corporation. (contact ) + * + * 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. + */ + +#include + +static GstTagList *received_tags = NULL; + +static gboolean +bus_handler (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + + switch (message->type) { + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + case GST_MESSAGE_WARNING: + case GST_MESSAGE_ERROR:{ + GError *gerror; + + gchar *debug; + + gst_message_parse_error (message, &gerror, &debug); + gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); + gst_message_unref (message); + g_error_free (gerror); + g_free (debug); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_TAG:{ + if (received_tags == NULL) { + gst_message_parse_tag (message, &received_tags); + } else { + GstTagList *tl = NULL, *ntl = NULL; + + gst_message_parse_tag (message, &tl); + if (tl) { + ntl = gst_tag_list_merge (received_tags, tl, GST_TAG_MERGE_PREPEND); + if (ntl) { + GST_LOG ("taglists merged: %" GST_PTR_FORMAT, ntl); + gst_tag_list_free (received_tags); + received_tags = ntl; + } + gst_tag_list_free (tl); + } + } + break; + } + default: + break; + } + + return TRUE; +} + + +static void +test_tags (const gchar * tag_str) +{ + GstElement *pipeline; + GstBus *bus; + GMainLoop *loop; + GstTagList *sent_tags; + gint i, j, n_recv, n_sent; + const gchar *name_sent, *name_recv; + const GValue *value_sent, *value_recv; + gboolean found; + gint comparison; + + GstElement *videotestsrc, *jpegenc, *metadatamux, *metadatademux, *fakesink; + GstTagSetter *setter; + + pipeline = gst_pipeline_new ("pipeline"); + fail_unless (pipeline != NULL); + + videotestsrc = gst_element_factory_make ("videotestsrc", "src"); + fail_unless (videotestsrc != NULL); + g_object_set (G_OBJECT (videotestsrc), "num-buffers", 1, NULL); + + jpegenc = gst_element_factory_make ("jpegenc", "enc"); + fail_unless (jpegenc != NULL); + + metadatamux = gst_element_factory_make ("metadatamux", "mux"); + g_object_set (G_OBJECT (metadatamux), "exif", TRUE, NULL); + fail_unless (metadatamux != NULL); + + metadatademux = gst_element_factory_make ("metadatademux", "demux"); + fail_unless (metadatademux != NULL); + + fakesink = gst_element_factory_make ("fakesink", "sink"); + fail_unless (fakesink != NULL); + + gst_bin_add_many (GST_BIN (pipeline), videotestsrc, jpegenc, metadatamux, + metadatademux, fakesink, NULL); + + fail_unless (gst_element_link_many (videotestsrc, jpegenc, metadatamux, + metadatademux, fakesink, NULL)); + + loop = g_main_loop_new (NULL, TRUE); + fail_unless (loop != NULL); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + gst_bus_add_watch (bus, bus_handler, loop); + gst_object_unref (bus); + + gst_element_set_state (pipeline, GST_STATE_READY); + + setter = GST_TAG_SETTER (metadatamux); + fail_unless (setter != NULL); + sent_tags = gst_structure_from_string (tag_str, NULL); + gst_tag_setter_merge_tags (setter, sent_tags, GST_TAG_MERGE_REPLACE); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + /* verify tags */ + fail_unless (received_tags != NULL); + n_recv = gst_structure_n_fields (received_tags); + n_sent = gst_structure_n_fields (sent_tags); + /* we also get e.g. an exif binary block */ + fail_unless (n_recv >= n_sent); + /* FIXME: compare taglits values */ + for (i = 0; i < n_sent; i++) { + name_sent = gst_structure_nth_field_name (sent_tags, i); + value_sent = gst_structure_get_value (sent_tags, name_sent); + found = FALSE; + for (j = 0; i < n_recv; j++) { + name_recv = gst_structure_nth_field_name (received_tags, j); + if (!strcmp (name_sent, name_recv)) { + value_recv = gst_structure_get_value (received_tags, name_recv); + comparison = gst_value_compare (value_sent, value_recv); + if (comparison != GST_VALUE_EQUAL) { + gchar *vs = g_strdup_value_contents (value_sent); + gchar *vr = g_strdup_value_contents (value_recv); + GST_DEBUG ("sent = %s:'%s', recv = %s:'%s'", + G_VALUE_TYPE_NAME (value_sent), vs, + G_VALUE_TYPE_NAME (value_recv), vr); + g_free (vs); + g_free (vr); + } + fail_unless (comparison == GST_VALUE_EQUAL, + "tag item %s has been received with different type or value", + name_sent); + found = TRUE; + break; + } + } + fail_unless (found, "tag item %s is lost", name_sent); + } + + gst_tag_list_free (received_tags); + received_tags = NULL; + gst_tag_list_free (sent_tags); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + g_main_loop_unref (loop); + g_object_unref (pipeline); +} + +GST_START_TEST (test_common_tags) +{ + test_tags ("taglist,title=\"test image\""); +} + +GST_END_TEST; + +GST_START_TEST (test_gps_tags) +{ + test_tags + ("taglist,geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=10.3"); + test_tags + ("taglist,geo-location-latitude=66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3"); + test_tags + ("taglist,geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3"); + test_tags + ("taglist,geo-location-latitude=66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3"); + test_tags + ("taglist,geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=10.3"); + test_tags + ("taglist,geo-location-latitude=-66.1,geo-location-longitude=22.5,geo-location-elevation=-10.3"); + test_tags + ("taglist,geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=10.3"); + test_tags + ("taglist,geo-location-latitude=-66.1,geo-location-longitude=-22.5,geo-location-elevation=-10.3"); +} + +GST_END_TEST; + + +Suite * +metadata_suite (void) +{ + Suite *s = suite_create ("MetaData"); + + TCase *tc_chain = tcase_create ("general"); + + /* time out after 60s, not the default 3 */ + tcase_set_timeout (tc_chain, 60); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_common_tags); + tcase_add_test (tc_chain, test_gps_tags); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = metadata_suite (); + + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/tests/icles/metadata_editor.c b/tests/icles/metadata_editor.c index 4c4afb205f..155d58676d 100644 --- a/tests/icles/metadata_editor.c +++ b/tests/icles/metadata_editor.c @@ -932,8 +932,8 @@ me_gst_bus_callback_view (GstBus * bus, GstMessage * message, gpointer data) if (ntl) { gst_tag_list_free (tag_list); tag_list = ntl; - gst_tag_list_free (tl); } + gst_tag_list_free (tl); } } /* remove whole chunk tags */