// GStreamer event filter that removes any image metadata. static gboolean remove_image(GstPad* pad, GstObject* parent, GstEvent* event) { GstTagList* tags = NULL; GstPad* sink = NULL; gboolean ret = false; switch (GST_EVENT_TYPE(event)) { case GST_EVENT_TAG: gst_event_parse_tag(event, &tags); gst_tag_list_remove_tag(tags, "image"); event = gst_event_new_tag(tags); break; case GST_EVENT_CAPS: sink = gst_element_get_static_pad(GST_ELEMENT(parent), "src"); ret = gst_pad_push_event(sink, event); gst_object_unref(sink); return ret; default: break; } return gst_pad_event_default(pad, parent, event); }
GstTagList * gst_droidcamsrc_exif_tags_from_jpeg_data (void *data, size_t size) { GstTagList *tags = NULL; ExifMem *mem = exif_mem_new (g_malloc0, g_realloc, g_free); ExifData *exif = exif_data_new_mem (mem); unsigned char *exif_data = NULL; void *_exif_data = NULL; unsigned int exif_data_size = 0; GstBuffer *buffer; ExifEntry *iso; int x, i; exif_data_load_data (exif, data, size); exif_data_set_data_type (exif, EXIF_DATA_TYPE_COMPRESSED); exif_data_save_data (exif, &exif_data, &exif_data_size); if (!exif_data_size) { goto out; } if (exif_data_size <= 6) { goto out; } /* dump the data. based on libexif code */ for (x = 0; x < EXIF_IFD_COUNT; x++) { if (exif->ifd[x] && exif->ifd[x]->count) { for (i = 0; i < exif->ifd[x]->count; i++) { char val[1024]; ExifEntry *e = exif->ifd[x]->entries[i]; GST_LOG ("Exif IFD: %s. Tag 0x%x (%s) = %s", exif_ifd_get_name (x), e->tag, exif_tag_get_name_in_ifd (e->tag, exif_entry_get_ifd (e)), exif_entry_get_value (e, val, sizeof (val))); } } } _exif_data = exif_data; exif_data += 6; exif_data_size -= 6; buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, exif_data, exif_data_size, 0, exif_data_size, NULL, NULL); tags = gst_tag_list_from_exif_buffer_with_tiff_header (buffer); gst_buffer_unref (buffer); /* We don't want these tags */ gst_tag_list_remove_tag (tags, GST_TAG_DEVICE_MANUFACTURER); gst_tag_list_remove_tag (tags, GST_TAG_DEVICE_MODEL); gst_tag_list_remove_tag (tags, GST_TAG_APPLICATION_NAME); gst_tag_list_remove_tag (tags, GST_TAG_DATE_TIME); /* we have a mess with ISO so we will just behave as N9 */ iso = exif_content_get_entry (exif->ifd[EXIF_IFD_EXIF], EXIF_TAG_ISO_SPEED_RATINGS); if (iso) { #ifdef __arm__ guint16 val = exif_get_short (iso->data, EXIF_BYTE_ORDER_MOTOROLA); #else guint16 val = exif_get_short (iso->data, EXIF_BYTE_ORDER_INTEL); #endif gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CAPTURING_ISO_SPEED, val, NULL); } /* TODO: the following are being dropped * * 0x213 EXIF_TAG_YCBCR_POSITIONING * 0x9004 EXIF_TAG_DATE_TIME_DIGITIZED * 0x9101 EXIF_TAG_COMPONENTS_CONFIGURATION * 0xa001 EXIF_TAG_COLOR_SPACE * 0xa002 EXIF_TAG_PIXEL_X_DIMENSION * 0xa003 EXIF_TAG_PIXEL_Y_DIMENSION * 0xa005 EXIF_TAG_INTEROPERABILITY_IFD_POINTER * thumbnail. * 0x100 EXIF_TAG_IMAGE_WIDTH * 0x101 EXIF_TAG_IMAGE_LENGTH * 0x9203 EXIF_TAG_BRIGHTNESS_VALUE * 0x9205 EXIF_TAG_MAX_APERTURE_VALUE * 0x9206 EXIF_TAG_SUBJECT_DISTANCE * 0x9208 EXIF_TAG_LIGHT_SOURCE * 0x9286 EXIF_TAG_USER_COMMENT */ out: if (_exif_data) { exif_mem_free (mem, _exif_data); } if (exif) { exif_data_free (exif); } exif_mem_unref (mem); return tags; }
static void bt_song_info_set_property (GObject * const object, const guint property_id, const GValue * const value, GParamSpec * const pspec) { const BtSongInfo *const self = BT_SONG_INFO (object); return_if_disposed (); switch (property_id) { case SONG_INFO_SONG: self->priv->song = BT_SONG (g_value_get_object (value)); g_object_try_weak_ref (self->priv->song); GST_DEBUG ("set the song for song-info: %p", self->priv->song); break; case SONG_INFO_FILE_NAME: g_free (self->priv->file_name); self->priv->file_name = g_value_dup_string (value); GST_DEBUG ("set the file-name for song_info: %s", self->priv->file_name); break; case SONG_INFO_INFO:{ const gchar *str = g_value_get_string (value); if ((self->priv->info != str) && (!self->priv->info || !str || strcmp (self->priv->info, str))) { g_free (self->priv->info); if (str) { self->priv->info = g_value_dup_string (value); gst_tag_list_add (self->priv->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DESCRIPTION, self->priv->info, NULL); } else { self->priv->info = NULL; gst_tag_list_remove_tag (self->priv->taglist, GST_TAG_DESCRIPTION); } GST_DEBUG ("set the info for song_info: %s", self->priv->info); } break; } case SONG_INFO_NAME:{ const gchar *str = g_value_get_string (value); if ((self->priv->name != str) && (!self->priv->name || !str || strcmp (self->priv->name, str))) { g_free (self->priv->name); if (str) { self->priv->name = g_value_dup_string (value); gst_tag_list_add (self->priv->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, self->priv->name, NULL); } else { self->priv->name = NULL; gst_tag_list_remove_tag (self->priv->taglist, GST_TAG_TITLE); } GST_DEBUG ("set the name for song_info: %s", self->priv->name); } break; } case SONG_INFO_GENRE:{ const gchar *str = g_value_get_string (value); if ((self->priv->genre != str) && (!self->priv->genre || !str || strcmp (self->priv->genre, str))) { g_free (self->priv->genre); if (str) { self->priv->genre = g_value_dup_string (value); gst_tag_list_add (self->priv->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, self->priv->genre, NULL); } else { self->priv->genre = NULL; gst_tag_list_remove_tag (self->priv->taglist, GST_TAG_GENRE); } GST_DEBUG ("set the genre for song_info: %s", self->priv->genre); } break; } case SONG_INFO_AUTHOR:{ const gchar *str = g_value_get_string (value); if ((self->priv->author != str) && (!self->priv->author || !str || strcmp (self->priv->author, str))) { g_free (self->priv->author); if (str) { self->priv->author = g_value_dup_string (value); gst_tag_list_add (self->priv->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ARTIST, self->priv->author, NULL); } else { self->priv->author = NULL; gst_tag_list_remove_tag (self->priv->taglist, GST_TAG_ARTIST); } GST_DEBUG ("set the author for song_info: %s", self->priv->author); } break; } case SONG_INFO_BPM:{ gulong val = g_value_get_ulong (value); if (self->priv->beats_per_minute != val) { self->priv->beats_per_minute = val; gst_tag_list_add (self->priv->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_BEATS_PER_MINUTE, (gdouble) self->priv->beats_per_minute, NULL); bt_song_info_tempo_changed (self); GST_DEBUG ("set the bpm for song_info: %lu", self->priv->beats_per_minute); } break; } case SONG_INFO_TPB:{ gulong val = g_value_get_ulong (value); if (self->priv->ticks_per_beat != val) { self->priv->ticks_per_beat = val; bt_song_info_tempo_changed (self); GST_DEBUG ("set the tpb for song_info: %lu", self->priv->ticks_per_beat); } } break; case SONG_INFO_BARS:{ gulong val = g_value_get_ulong (value); if (self->priv->bars != val) { self->priv->bars = val; bt_song_info_tempo_changed (self); GST_DEBUG ("set the bars for song_info: %lu", self->priv->bars); } break; } case SONG_INFO_CREATE_DTS:{ const gchar *const dts = g_value_get_string (value); if (dts) { if (strlen (dts) == DTS_LEN) { strcpy (self->priv->create_dts, dts); } } else { time_t now = time (NULL); /* this is ISO 8601 Date and Time Format * %F Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99) * %T The time in 24-hour notation (%H:%M:%S). (SU) */ strftime (self->priv->create_dts, DTS_LEN + 1, "%FT%TZ", gmtime (&now)); } break; } case SONG_INFO_CHANGE_DTS:{ const gchar *const dts = g_value_get_string (value); if (dts) { if (strlen (dts) == DTS_LEN) { struct tm tm = { 0, }; strcpy (self->priv->change_dts, dts); // parse date and update tag strptime (dts, "%FT%TZ", &tm); g_date_set_time_t (self->priv->tag_date, mktime (&tm)); gst_tag_list_add (self->priv->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, self->priv->tag_date, NULL); } } else { time_t now = time (NULL); strftime (self->priv->change_dts, DTS_LEN + 1, "%FT%TZ", gmtime (&now)); g_date_set_time_t (self->priv->tag_date, now); gst_tag_list_add (self->priv->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, self->priv->tag_date, NULL); } break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static GstEvent * gst_rg_volume_tag_event (GstRgVolume * self, GstEvent * event) { GstTagList *tag_list; gboolean has_track_gain, has_track_peak, has_album_gain, has_album_peak; gboolean has_ref_level; g_return_val_if_fail (event != NULL, NULL); g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TAG, event); gst_event_parse_tag (event, &tag_list); if (gst_tag_list_is_empty (tag_list)) return event; has_track_gain = gst_tag_list_get_double (tag_list, GST_TAG_TRACK_GAIN, &self->track_gain); has_track_peak = gst_tag_list_get_double (tag_list, GST_TAG_TRACK_PEAK, &self->track_peak); has_album_gain = gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_GAIN, &self->album_gain); has_album_peak = gst_tag_list_get_double (tag_list, GST_TAG_ALBUM_PEAK, &self->album_peak); has_ref_level = gst_tag_list_get_double (tag_list, GST_TAG_REFERENCE_LEVEL, &self->reference_level); if (!has_track_gain && !has_track_peak && !has_album_gain && !has_album_peak) return event; if (has_ref_level && (has_track_gain || has_album_gain) && (ABS (self->reference_level - RG_REFERENCE_LEVEL) > 1.e-6)) { /* Log a message stating the amount of adjustment that is applied below. */ GST_DEBUG_OBJECT (self, "compensating for reference level difference by %" GAIN_FORMAT, RG_REFERENCE_LEVEL - self->reference_level); } if (has_track_gain) { self->track_gain += RG_REFERENCE_LEVEL - self->reference_level; } if (has_album_gain) { self->album_gain += RG_REFERENCE_LEVEL - self->reference_level; } /* Ignore values that are obviously invalid. */ if (G_UNLIKELY (has_track_gain && !VALID_GAIN (self->track_gain))) { GST_DEBUG_OBJECT (self, "ignoring bogus track gain value %" GAIN_FORMAT, self->track_gain); has_track_gain = FALSE; } if (G_UNLIKELY (has_track_peak && !VALID_PEAK (self->track_peak))) { GST_DEBUG_OBJECT (self, "ignoring bogus track peak value %" PEAK_FORMAT, self->track_peak); has_track_peak = FALSE; } if (G_UNLIKELY (has_album_gain && !VALID_GAIN (self->album_gain))) { GST_DEBUG_OBJECT (self, "ignoring bogus album gain value %" GAIN_FORMAT, self->album_gain); has_album_gain = FALSE; } if (G_UNLIKELY (has_album_peak && !VALID_PEAK (self->album_peak))) { GST_DEBUG_OBJECT (self, "ignoring bogus album peak value %" PEAK_FORMAT, self->album_peak); has_album_peak = FALSE; } /* Clamp peaks >1.0. Float based decoders can produce spurious samples >1.0, * cutting these files back to 1.0 should not cause any audible distortion. * This is most often seen with Vorbis files. */ if (has_track_peak && self->track_peak > 1.) { GST_DEBUG_OBJECT (self, "clamping track peak %" PEAK_FORMAT " to 1.0", self->track_peak); self->track_peak = 1.0; } if (has_album_peak && self->album_peak > 1.) { GST_DEBUG_OBJECT (self, "clamping album peak %" PEAK_FORMAT " to 1.0", self->album_peak); self->album_peak = 1.0; } self->has_track_gain |= has_track_gain; self->has_track_peak |= has_track_peak; self->has_album_gain |= has_album_gain; self->has_album_peak |= has_album_peak; event = (GstEvent *) gst_mini_object_make_writable (GST_MINI_OBJECT (event)); gst_event_parse_tag (event, &tag_list); gst_tag_list_remove_tag (tag_list, GST_TAG_TRACK_GAIN); gst_tag_list_remove_tag (tag_list, GST_TAG_TRACK_PEAK); gst_tag_list_remove_tag (tag_list, GST_TAG_ALBUM_GAIN); gst_tag_list_remove_tag (tag_list, GST_TAG_ALBUM_PEAK); gst_tag_list_remove_tag (tag_list, GST_TAG_REFERENCE_LEVEL); gst_rg_volume_update_gain (self); if (gst_tag_list_is_empty (tag_list)) { gst_event_unref (event); event = NULL; } return event; }