static inline gboolean gst_jpeg_parse_skip_marker (GstJpegParse * parse, GstByteReader * reader, guint8 marker) { guint16 size = 0; if (!gst_byte_reader_get_uint16_be (reader, &size)) return FALSE; #ifndef GST_DISABLE_DEBUG /* We'd pry the id of the skipped application segment */ if (marker >= APP0 && marker <= APP15) { const gchar *id_str = NULL; if (gst_byte_reader_peek_string_utf8 (reader, &id_str)) { GST_DEBUG_OBJECT (parse, "unhandled marker %x: '%s' skiping %u bytes", marker, id_str ? id_str : "(NULL)", size); } else { GST_DEBUG_OBJECT (parse, "unhandled marker %x skiping %u bytes", marker, size); } } #else GST_DEBUG_OBJECT (parse, "unhandled marker %x skiping %u bytes", marker, size); #endif // GST_DISABLE_DEBUG if (!gst_byte_reader_skip (reader, size - 2)) return FALSE; return TRUE; }
static inline gboolean gst_jpeg_parse_app1 (GstJpegParse * parse, GstByteReader * reader) { guint16 size = 0; const gchar *id_str; const guint8 *data = NULL; if (!gst_byte_reader_get_uint16_be (reader, &size)) return FALSE; size -= 2; /* 2 bytes for the mark */ if (!gst_byte_reader_peek_string_utf8 (reader, &id_str)) return FALSE; if (!strncmp (id_str, "Exif", 4)) { /* skip id + NUL + padding */ if (!gst_byte_reader_skip (reader, 6)) return FALSE; size -= 6; /* handle exif metadata */ if (!gst_byte_reader_get_data (reader, size, &data)) return FALSE; extract_and_queue_tags (parse, size, (guint8 *) data, gst_tag_list_from_exif_buffer_with_tiff_header); GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes", APP1, id_str, size); } else if (!strncmp (id_str, "http://ns.adobe.com/xap/1.0/", 28)) { /* skip the id + NUL */ if (!gst_byte_reader_skip (reader, 29)) return FALSE; size -= 29; /* handle xmp metadata */ if (!gst_byte_reader_get_data (reader, size, &data)) return FALSE; extract_and_queue_tags (parse, size, (guint8 *) data, gst_tag_list_from_xmp_buffer); GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes", APP1, id_str, size); } else { if (!gst_jpeg_parse_skip_marker (parse, reader, APP1)) return FALSE; } return TRUE; }
/* Ideas from gstjpegparse.c */ GstTagList * gst_droidcamsrc_exif_tags_from_jpeg_data (void *data, size_t size) { GstByteReader reader; guint16 len = 0; const gchar *id; const guint8 *exif = NULL; GstBuffer *buff; GstTagList *tags = NULL; void *app1 = memmem (data, size, marker, 2); if (!app1) { GST_ERROR ("No tags found"); goto out; } size -= (app1 - data); gst_byte_reader_init (&reader, app1, size); if (!gst_byte_reader_skip (&reader, 2)) { GST_ERROR ("Not enough jpeg data for tags"); goto out; } if (!gst_byte_reader_get_uint16_be (&reader, &len)) { GST_ERROR ("Failed to get APP1 size"); goto out; } len -= 2; /* for the marker itself */ if (!gst_byte_reader_peek_string_utf8 (&reader, &id)) { goto out; } if (!strncmp (id, "Exif", 4)) { /* id + NUL + padding */ if (!gst_byte_reader_skip (&reader, 6)) { goto out; } len -= 6; if (!gst_byte_reader_get_data (&reader, len, &exif)) { goto out; } buff = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, (gpointer) exif, len, 0, len, NULL, NULL); tags = gst_tag_list_from_exif_buffer_with_tiff_header (buff); gst_buffer_unref (buff); return tags; } out: return NULL; }