diff --git a/gst-libs/gst/riff/riff-ids.h b/gst-libs/gst/riff/riff-ids.h index 9542c59622..690a6513ad 100644 --- a/gst-libs/gst/riff/riff-ids.h +++ b/gst-libs/gst/riff/riff-ids.h @@ -71,6 +71,7 @@ G_BEGIN_DECLS #define GST_RIFF_LIST_INFO GST_MAKE_FOURCC ('I','N','F','O') #define GST_RIFF_LIST_AVIX GST_MAKE_FOURCC ('A','V','I','X') #define GST_RIFF_LIST_adtl GST_MAKE_FOURCC ('a','d','t','l') +#define GST_RIFF_LIST_ncdt GST_MAKE_FOURCC ('n','c','d','t') /* fcc types */ #define GST_RIFF_FCC_vids GST_MAKE_FOURCC ('v','i','d','s') @@ -112,6 +113,9 @@ G_BEGIN_DECLS #define GST_RIFF_INFO_IAAR GST_MAKE_FOURCC ('I','A','A','R') /* album artist */ #define GST_RIFF_INFO_ITRK GST_MAKE_FOURCC ('I','T','R','K') /* track number */ +/* ncdt types - see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCDT */ +#define GST_RIFF_LIST_nctg GST_MAKE_FOURCC ('n','c','t','g') + /*********Chunk Names***************/ #define GST_RIFF_FF00 GST_MAKE_FOURCC (0xFF,0xFF,0x00,0x00) #define GST_RIFF_00 GST_MAKE_FOURCC ('0', '0',0x00,0x00) diff --git a/gst-libs/gst/riff/riff-read.c b/gst-libs/gst/riff/riff-read.c index 8bc5fa682e..6afaa1ef13 100644 --- a/gst-libs/gst/riff/riff-read.c +++ b/gst-libs/gst/riff/riff-read.c @@ -619,6 +619,40 @@ too_small: } } +static void +parse_tag_value (GstElement * element, 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 (element, "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 (element, "could not extract %s tag", type); + } +} + /** * gst_riff_parse_info: * @element: caller element (used for debugging/error). @@ -762,38 +796,10 @@ gst_riff_parse_info (GstElement * element, } if (type != NULL && ptr[0] != '\0') { - static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING", - "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL - }; - GType tag_type; - gchar *val; - GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s", GST_FOURCC_ARGS (tag), type); - 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 (element, "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 (element, "could not extract %s tag", type); - } + parse_tag_value (element, taglist, type, ptr, tsize); } if (tsize & 1) { @@ -817,3 +823,136 @@ gst_riff_parse_info (GstElement * element, return; } + +/** + * gst_riff_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. + * + * Since: 1.4 + */ +void +gst_riff_parse_ncdt (GstElement * element, + 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 (element, "tag chunk", ptr, MIN (tsize + 8, left)); + + left -= 8; + ptr += 8; + + GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u", + GST_FOURCC_ARGS (tag), tsize); + + if (tsize > left) { + GST_WARNING_OBJECT (element, + "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 ("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 (element, "mapped tag %u to tag %s", sub_tag, + type); + + parse_tag_value (element, taglist, type, ptr, sub_size); + } + + ptr += sub_size; + tsize -= sub_size; + } + break; + default: + type = NULL; + GST_WARNING_OBJECT (element, + "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 (element, "extracted tags: %" GST_PTR_FORMAT, taglist); + *_taglist = taglist; + } else { + *_taglist = NULL; + gst_tag_list_unref (taglist); + } + gst_buffer_unmap (buf, &info); + + return; + } diff --git a/gst-libs/gst/riff/riff-read.h b/gst-libs/gst/riff/riff-read.h index 918b997628..57e8bfe260 100644 --- a/gst-libs/gst/riff/riff-read.h +++ b/gst-libs/gst/riff/riff-read.h @@ -77,6 +77,9 @@ void gst_riff_parse_info (GstElement * element, GstBuffer * buf, GstTagList ** taglist); +void gst_riff_parse_ncdt (GstElement * element, + GstBuffer * buf, + GstTagList ** taglist); /* * Init. */