diff --git a/ChangeLog b/ChangeLog index 364df12c89..99b9f3bfa0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2009-01-05 Mark Nauwelaerts + + * gst/qtdemux/qtdemux.c: (qtdemux_tag_add_str), + (qtdemux_tag_add_tmpo), (qtdemux_tag_add_covr), + (qtdemux_tag_add_date), (qtdemux_tag_add_gnre), + (qtdemux_tag_add_blob), (qtdemux_parse_udta): + * gst/qtdemux/qtdemux.h: + * gst/qtdemux/quicktime.c: (plugin_init): + Streamline tag handling and pass unparsed tags as binary blob + in private tag. + 2009-01-05 Sebastian Dröge * gst/audiofx/Makefile.am: diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index a72bd7fa09..bcdff18636 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -3882,7 +3882,8 @@ unknown_stream: } static void -qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, GNode * node) +qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, const char *dummy, + GNode * node) { const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; GNode *data; @@ -3955,7 +3956,8 @@ qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1, } static void -qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, GNode * node) +qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy, + GNode * node) { GNode *data; int len; @@ -3981,7 +3983,8 @@ qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, GNode * node) } static void -qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, GNode * node) +qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy, + GNode * node) { GNode *data; int len; @@ -4005,7 +4008,8 @@ qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, GNode * node) } static void -qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, GNode * node) +qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy, + GNode * node) { GNode *data; char *s; @@ -4039,7 +4043,8 @@ qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, GNode * node) } static void -qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node) +qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy, + GNode * node) { static const gchar *genres[] = { "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco", @@ -4092,12 +4097,88 @@ qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node) } } +typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, + const char *tag, const char *tag_bis, GNode * node); + +static const struct +{ + guint32 fourcc; + const gchar *gst_tag; + const gchar *gst_tag_bis; + const GstQTDemuxAddTagFunc func; +} add_funcs[] = { + { + FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { + FOURCC__grp, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { + FOURCC__wrt, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { + FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { + FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { + FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { + FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { + FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { + FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { + FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, { + FOURCC__too, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { + FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, { + FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, + qtdemux_tag_add_num}, { + FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, + qtdemux_tag_add_num}, { + FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, { + FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, { + FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, { + FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, { + FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, { + FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str} +}; + +static void +qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux) +{ + gint len; + guint8 *data; + GstBuffer *buf; + gchar *media_type, *style; + GstCaps *caps; + + data = node->data; + len = QT_UINT32 (data); + buf = gst_buffer_new_and_alloc (len); + memcpy (GST_BUFFER_DATA (buf), data, len); + + /* heuristic to determine style of tag */ + if (QT_FOURCC (data + 4) == FOURCC_____ || + (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data)) + style = "itunes"; + else if (demux->major_brand == GST_MAKE_FOURCC ('q', 't', ' ', ' ')) + style = "quicktime"; + /* fall back to assuming iso/3gp tag style */ + else + style = "iso"; + + media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag", + g_ascii_tolower (data[4]), g_ascii_tolower (data[5]), + g_ascii_tolower (data[6]), g_ascii_tolower (data[7])); + caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL); + gst_buffer_set_caps (buf, caps); + gst_caps_unref (caps); + g_free (media_type); + + GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT, + GST_BUFFER_SIZE (buf), caps); + + gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND, + GST_QT_DEMUX_PRIVATE_TAG, buf, NULL); + gst_buffer_unref (buf); +} + static void qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta) { GNode *meta; GNode *ilst; GNode *node; + gint i; meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta); if (meta != NULL) { @@ -4114,107 +4195,18 @@ qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta) GST_DEBUG_OBJECT (qtdemux, "new tag list"); qtdemux->tag_list = gst_tag_list_new (); - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__nam); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_TITLE, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__ART); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node); - } else { - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__wrt); + for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) { + node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc); if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node); - } else { - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__grp); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node); - } + add_funcs[i].func (qtdemux, add_funcs[i].gst_tag, + add_funcs[i].gst_tag_bis, node); + g_node_destroy (node); } } - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__alb); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_ALBUM, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__cpy); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_COPYRIGHT, node); - } else { - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_cprt); - if (node) - qtdemux_tag_add_str (qtdemux, GST_TAG_COPYRIGHT, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__cmt); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_COMMENT, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__des); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_DESCRIPTION, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__day); - if (node) { - qtdemux_tag_add_date (qtdemux, GST_TAG_DATE, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__too); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_COMMENT, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_trkn); - if (node) { - qtdemux_tag_add_num (qtdemux, GST_TAG_TRACK_NUMBER, - GST_TAG_TRACK_COUNT, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disc); - if (node) { - qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER, - GST_TAG_ALBUM_VOLUME_COUNT, node); - } else { - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disk); - if (node) { - qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER, - GST_TAG_ALBUM_VOLUME_COUNT, node); - } - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_gnre); - if (node) { - qtdemux_tag_add_gnre (qtdemux, GST_TAG_GENRE, node); - } else { - node = qtdemux_tree_get_child_by_type (ilst, FOURCC__gen); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_GENRE, node); - } - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_tmpo); - if (node) { - qtdemux_tag_add_tmpo (qtdemux, GST_TAG_BEATS_PER_MINUTE, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_covr); - if (node) { - qtdemux_tag_add_covr (qtdemux, GST_TAG_PREVIEW_IMAGE, node); - } - - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_keyw); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_KEYWORDS, node); - } else { - node = qtdemux_tree_get_child_by_type (ilst, FOURCC_kywd); - if (node) { - qtdemux_tag_add_str (qtdemux, GST_TAG_KEYWORDS, node); - } - } + /* parsed nodes have been removed, pass along remainder as blob */ + g_node_children_foreach (ilst, G_TRAVERSE_ALL, + (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux); } diff --git a/gst/qtdemux/qtdemux.h b/gst/qtdemux/qtdemux.h index cb67096be9..bdc36c4bd7 100644 --- a/gst/qtdemux/qtdemux.h +++ b/gst/qtdemux/qtdemux.h @@ -42,6 +42,9 @@ GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug); #define GST_QTDEMUX_CAST(obj) ((GstQTDemux *)(obj)) +/* qtdemux produces these for atoms it cannot parse */ +#define GST_QT_DEMUX_PRIVATE_TAG "private-qt-tag" + #define GST_QTDEMUX_MAX_STREAMS 8 typedef struct _GstQTDemux GstQTDemux; diff --git a/gst/qtdemux/quicktime.c b/gst/qtdemux/quicktime.c index f7b880c805..dc92fcff4d 100644 --- a/gst/qtdemux/quicktime.c +++ b/gst/qtdemux/quicktime.c @@ -35,6 +35,11 @@ plugin_init (GstPlugin * plugin) bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); #endif /* ENABLE_NLS */ + /* ensure private tag is registered */ + gst_tag_register (GST_QT_DEMUX_PRIVATE_TAG, GST_TAG_FLAG_META, + GST_TYPE_BUFFER, "QT atom", "unparsed QT tag atom", + gst_tag_merge_use_first); + if (!gst_element_register (plugin, "qtdemux", GST_RANK_PRIMARY, GST_TYPE_QTDEMUX)) return FALSE;