From: Marco Ballesio Date: Wed, 15 Apr 2009 17:10:04 +0000 (+0300) Subject: qtdemux: implement 3GPP (TS 26.244 V8.0.0) Asset metadata handling, Fixes #132193 X-Git-Tag: RELEASE-0.10.15~298 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=94d5d24cf0e72752d6d7d10c8357e48eaf366ca2;p=platform%2Fupstream%2Fgst-plugins-good.git qtdemux: implement 3GPP (TS 26.244 V8.0.0) Asset metadata handling, Fixes #132193 Implements 3gpp iso metadata tags which are different from mov udta atoms. --- diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index 7ff8d68..afa72c1 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -4335,6 +4335,111 @@ unknown_stream: } } +static inline gboolean +qtdemux_is_string_3gp (GstQTDemux * qtdemux, guint32 fourcc) +{ + /* Detect if the tag must be handled as 3gpp - i18n metadata. The first + * check is for catching all the possible brands, e.g. 3gp4,3gp5,.. and + * handling properly the tags present in more than one brand.*/ + return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 255, 0)) == + GST_MAKE_FOURCC ('3', 'g', 'p', 0) + && (fourcc == FOURCC_cprt || fourcc == FOURCC_gnre + || fourcc == FOURCC_kywd)) || fourcc == FOURCC_titl + || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth + || fourcc == FOURCC_albm; +} + +static void +qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag, + const char *dummy, GNode * node) +{ + const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; + int offset; + char *name; + gdouble longitude, latitude, altitude; + + offset = 14; + + /* TODO: language code skipped */ + + name = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, + -1, env_vars); + + if (!name) { + GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); + } + + /* +1 = skip location role byte */ + offset += strlen (name) + 1 + 1; + longitude = QT_FP32 ((guint8 *) node->data + offset); + + offset += 4; + latitude = QT_FP32 ((guint8 *) node->data + offset); + + offset += 4; + altitude = QT_FP32 ((guint8 *) node->data + offset); + + gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, + GST_TAG_GEO_LOCATION_NAME, name, + GST_TAG_GEO_LOCATION_LATITUDE, latitude, + GST_TAG_GEO_LOCATION_LONGITUDE, longitude, + GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL); + + /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */ + + g_free (name); +} + + +static void +qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy, + GNode * node) +{ + guint16 y; + GDate *date; + + y = QT_UINT16 ((guint8 *) node->data + 12); + GST_DEBUG_OBJECT (qtdemux, "year: %u", y); + + date = g_date_new_dmy (1, 1, y); + gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL); + g_date_free (date); +} + +static void +qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag, + const char *dummy, GNode * node) +{ + int offset; + char *tag_str = NULL; + guint32 entity; + guint16 table; + + + offset = 12; + entity = QT_FOURCC ((guint8 *) node->data + offset); + + offset += 4; + table = QT_UINT16 ((guint8 *) node->data + offset); + + /* Language code skipped */ + + offset += 4; + + /* Tag format: "XXXX://Y[YYYY]/classification info string" + * XXXX: classification entity, fixed length 4 chars. + * Y[YYYY]: classification table, max 5 chars. + */ + tag_str = g_strdup_printf ("%" GST_FOURCC_FORMAT "://%u/%s", + GST_FOURCC_ARGS (entity), table, (char *) node->data + offset); + GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str); + + gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag, + tag_str, NULL); + + g_free (tag_str); +} + static void qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, const char *dummy, GNode * node) @@ -4365,11 +4470,16 @@ qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, const char *dummy, } else { len = QT_UINT32 (node->data); type = QT_UINT32 ((guint8 *) node->data + 4); - if (type & 0xa9000000) { + if ((type >> 24) == 0xa9) { /* Type starts with the (C) symbol, so the next 32 bits are * the language code, which we ignore */ offset = 12; GST_DEBUG_OBJECT (qtdemux, "found international text tag"); + } else if (qtdemux_is_string_3gp (qtdemux, + QT_FOURCC ((guint8 *) node->data + 4))) { + offset = 14; + /* 16-bit Language code is ignored here as well */ + GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag"); } else { offset = 8; GST_DEBUG_OBJECT (qtdemux, "found normal text tag"); @@ -4563,15 +4673,21 @@ static const struct } add_funcs[] = { { FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { + FOURCC_titl, 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_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { + FOURCC_auth, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { + FOURCC_albm, 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_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, { + FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, { FOURCC__too, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, { @@ -4585,7 +4701,10 @@ static const struct 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}, { - FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str} + FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { + FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, { + FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL, + qtdemux_tag_add_classification} }; static void diff --git a/gst/qtdemux/qtdemux.h b/gst/qtdemux/qtdemux.h index bdc36c4..d227b7f 100644 --- a/gst/qtdemux/qtdemux.h +++ b/gst/qtdemux/qtdemux.h @@ -44,6 +44,7 @@ GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug); /* qtdemux produces these for atoms it cannot parse */ #define GST_QT_DEMUX_PRIVATE_TAG "private-qt-tag" +#define GST_QT_DEMUX_CLASSIFICATION_TAG "classification" #define GST_QTDEMUX_MAX_STREAMS 8 diff --git a/gst/qtdemux/qtdemux_fourcc.h b/gst/qtdemux/qtdemux_fourcc.h index cbf5b15..aa9a1f2 100644 --- a/gst/qtdemux/qtdemux_fourcc.h +++ b/gst/qtdemux/qtdemux_fourcc.h @@ -140,6 +140,17 @@ G_BEGIN_DECLS #define FOURCC_keyw GST_MAKE_FOURCC('k','e','y','w') #define FOURCC_kywd GST_MAKE_FOURCC('k','y','w','d') +/* 3gpp asset meta data fourcc */ +#define FOURCC_titl GST_MAKE_FOURCC('t','i','t','l') +#define FOURCC_dscp GST_MAKE_FOURCC('d','s','c','p') +#define FOURCC_perf GST_MAKE_FOURCC('p','e','r','f') +#define FOURCC_auth GST_MAKE_FOURCC('a','u','t','h') +#define FOURCC_rtng GST_MAKE_FOURCC('r','t','n','g') +#define FOURCC_clsf GST_MAKE_FOURCC('c','l','s','f') +#define FOURCC_loci GST_MAKE_FOURCC('l','o','c','i') +#define FOURCC_albm GST_MAKE_FOURCC('a','l','b','m') +#define FOURCC_yrrc GST_MAKE_FOURCC('y','r','r','c') + /* ISO Motion JPEG 2000 fourcc */ #define FOURCC_mjp2 GST_MAKE_FOURCC('m','j','p','2') #define FOURCC_jp2h GST_MAKE_FOURCC('j','p','2','h') diff --git a/gst/qtdemux/qtdemux_types.c b/gst/qtdemux/qtdemux_types.c index 357fee5..d2b7e5a 100644 --- a/gst/qtdemux/qtdemux_types.c +++ b/gst/qtdemux/qtdemux_types.c @@ -95,14 +95,19 @@ static const QtNodeType qt_node_types[] = { {FOURCC_meta, "meta", 0, qtdemux_dump_unknown}, {FOURCC_ilst, "ilst", QT_FLAG_CONTAINER,}, {FOURCC__nam, "Name", QT_FLAG_CONTAINER,}, + {FOURCC_titl, "Title", QT_FLAG_CONTAINER,}, {FOURCC__ART, "Artist", QT_FLAG_CONTAINER,}, + {FOURCC_auth, "Author", QT_FLAG_CONTAINER,}, + {FOURCC_perf, "Performer", QT_FLAG_CONTAINER,}, {FOURCC__wrt, "Writer", QT_FLAG_CONTAINER,}, {FOURCC__grp, "Group", QT_FLAG_CONTAINER,}, {FOURCC__alb, "Album", QT_FLAG_CONTAINER,}, + {FOURCC_albm, "Album", QT_FLAG_CONTAINER,}, {FOURCC__day, "Date", QT_FLAG_CONTAINER,}, {FOURCC__cpy, "Copyright", QT_FLAG_CONTAINER,}, {FOURCC__cmt, "Comment", QT_FLAG_CONTAINER,}, {FOURCC__des, "Description", QT_FLAG_CONTAINER,}, + {FOURCC_dscp, "Description", QT_FLAG_CONTAINER,}, {FOURCC__req, "Requirement", QT_FLAG_CONTAINER,}, {FOURCC__enc, "Encoder", QT_FLAG_CONTAINER,}, {FOURCC_gnre, "Genre", QT_FLAG_CONTAINER,}, @@ -127,8 +132,11 @@ static const QtNodeType qt_node_types[] = { {FOURCC_ctts, "Composition time to sample", 0, qtdemux_dump_ctts}, {FOURCC_XiTh, "XiTh", 0}, {FOURCC_XdxT, "XdxT", 0}, + {FOURCC_loci, "loci", 0}, + {FOURCC_clsf, "clsf", 0}, {0, "unknown", 0,}, }; + static const int n_qt_node_types = sizeof (qt_node_types) / sizeof (qt_node_types[0]); diff --git a/gst/qtdemux/quicktime.c b/gst/qtdemux/quicktime.c index 9788834..a2da40f 100644 --- a/gst/qtdemux/quicktime.c +++ b/gst/qtdemux/quicktime.c @@ -41,6 +41,10 @@ plugin_init (GstPlugin * plugin) GST_TYPE_BUFFER, "QT atom", "unparsed QT tag atom", gst_tag_merge_use_first); + gst_tag_register (GST_QT_DEMUX_CLASSIFICATION_TAG, GST_TAG_FLAG_META, + G_TYPE_STRING, GST_QT_DEMUX_CLASSIFICATION_TAG, "content classification", + gst_tag_merge_use_first); + if (!gst_element_register (plugin, "qtdemux", GST_RANK_PRIMARY, GST_TYPE_QTDEMUX)) return FALSE;