diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index 774da5cd10..dc455fca62 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -53,7 +53,7 @@ #include "avi-ids.h" #include #include - +#include #define DIV_ROUND_UP(s,v) (((s) + ((v)-1)) / (v)) @@ -3687,6 +3687,170 @@ non_parsable: gst_buffer_unmap (buf, &map); } +static void +parse_tag_value (GstAviDemux * avi, GstTagList * taglist, const gchar * type, + guint8 * ptr, guint tsize) +{ + static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING", + "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL + }; + GType tag_type; + gchar *val; + + tag_type = gst_tag_get_type (type); + val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars); + + if (val != NULL) { + if (tag_type == G_TYPE_STRING) { + gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL); + } else { + GValue tag_val = { 0, }; + + g_value_init (&tag_val, tag_type); + if (gst_value_deserialize (&tag_val, val)) { + gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type, &tag_val); + } else { + GST_WARNING_OBJECT (avi, "could not deserialize '%s' into a " + "tag %s of type %s", val, type, g_type_name (tag_type)); + } + g_value_unset (&tag_val); + } + g_free (val); + } else { + GST_WARNING_OBJECT (avi, "could not extract %s tag", type); + } +} + +/* + * gst_avi_demux_parse_ncdt: + * @element: caller element (used for debugging/error). + * @buf: input data to be used for parsing, stripped from header. + * @taglist: a pointer to a taglist (returned by this function) + * containing information about this stream. May be + * NULL if no supported tags were found. + * + * Parses Nikon metadata from input data. + */ +static void +gst_avi_demux_parse_ncdt (GstAviDemux * avi, GstBuffer * buf, + GstTagList ** _taglist) +{ + GstMapInfo info; + guint8 *ptr; + gsize left; + guint tsize; + guint32 tag; + const gchar *type; + GstTagList *taglist; + + g_return_if_fail (_taglist != NULL); + + if (!buf) { + *_taglist = NULL; + return; + } + gst_buffer_map (buf, &info, GST_MAP_READ); + + taglist = gst_tag_list_new_empty (); + + ptr = info.data; + left = info.size; + + while (left > 8) { + tag = GST_READ_UINT32_LE (ptr); + tsize = GST_READ_UINT32_LE (ptr + 4); + + GST_MEMDUMP_OBJECT (avi, "tag chunk", ptr, MIN (tsize + 8, left)); + + left -= 8; + ptr += 8; + + GST_DEBUG_OBJECT (avi, "tag %" GST_FOURCC_FORMAT ", size %u", + GST_FOURCC_ARGS (tag), tsize); + + if (tsize > left) { + GST_WARNING_OBJECT (avi, + "Tagsize %d is larger than available data %" G_GSIZE_FORMAT, + tsize, left); + tsize = left; + } + + /* find out the type of metadata */ + switch (tag) { + case GST_RIFF_LIST_nctg: + while (tsize > 4) { + guint16 sub_tag = GST_READ_UINT16_LE (ptr); + guint16 sub_size = GST_READ_UINT16_LE (ptr + 2); + + tsize -= 4; + ptr += 4; + + GST_DEBUG_OBJECT (avi, "sub-tag %u, size %u", sub_tag, sub_size); + /* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG + * for some reason the sub_tag has a +2 offset + */ + switch (sub_tag) { + case 0x03: /* Make */ + type = GST_TAG_DEVICE_MANUFACTURER; + break; + case 0x04: /* Model */ + type = GST_TAG_DEVICE_MODEL; + break; + /* TODO: 0x05: is software version, like V1.0 */ + case 0x06: /* Software */ + type = GST_TAG_ENCODER; + break; + case 0x13: /* CreationDate */ + type = GST_TAG_DATE_TIME; + if (ptr[4] == ':') + ptr[4] = '-'; + if (ptr[7] == ':') + ptr[7] = '-'; + break; + default: + type = NULL; + break; + } + if (type != NULL && ptr[0] != '\0') { + GST_DEBUG_OBJECT (avi, "mapped tag %u to tag %s", sub_tag, type); + + parse_tag_value (avi, taglist, type, ptr, sub_size); + } + + ptr += sub_size; + tsize -= sub_size; + } + break; + default: + type = NULL; + GST_WARNING_OBJECT (avi, + "Unknown ncdt (metadata) tag entry %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (tag)); + break; + } + + if (tsize & 1) { + tsize++; + if (tsize > left) + tsize = left; + } + + ptr += tsize; + left -= tsize; + } + + if (!gst_tag_list_is_empty (taglist)) { + GST_INFO_OBJECT (avi, "extracted tags: %" GST_PTR_FORMAT, taglist); + *_taglist = taglist; + } else { + *_taglist = NULL; + gst_tag_list_unref (taglist); + } + gst_buffer_unmap (buf, &info); + + return; +} + /* * Read full AVI headers. */ @@ -3798,7 +3962,7 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi) case GST_RIFF_LIST_ncdt: gst_buffer_unmap (sub, &map); gst_buffer_resize (sub, 4, -1); - gst_riff_parse_ncdt (element, sub, &tags); + gst_avi_demux_parse_ncdt (avi, sub, &tags); if (tags) { if (avi->globaltags) { gst_tag_list_insert (avi->globaltags, tags,