riff: add support for nikon tags

Nikon cameras store metadata in a custom format. Add parsing of the chunk and
extract some initial data.
API: gst_riff_parse_ncdt()
Fixes #636143
This commit is contained in:
Stefan Sauer 2014-01-04 21:31:07 +01:00
parent f0b655e1ad
commit f653aa8c85
3 changed files with 175 additions and 29 deletions

View file

@ -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)

View file

@ -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;
}

View file

@ -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.
*/