libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

commit dcd11a972978dc4b13d36ab3dfebeff2b29da361
parent 936a85ffbd5a81011f6d7f5d3e4c30e12eac8757
Author: LRN <lrn1986@gmail.com>
Date:   Mon, 20 Aug 2012 06:55:11 +0000

More GStreamer fixes

Correct stream tree walking.
Better duration handling (new metadata types).
Send unknown tags as key=value paris.
GStreamer flv test.

Diffstat:
Msrc/include/extractor.h | 7++++++-
Msrc/main/extractor_metatypes.c | 7+++++++
Msrc/plugins/gstreamer_extractor.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/plugins/test_gstreamer.c | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 272 insertions(+), 9 deletions(-)

diff --git a/src/include/extractor.h b/src/include/extractor.h @@ -377,7 +377,12 @@ enum EXTRACTOR_MetaType EXTRACTOR_METATYPE_VIDEO_LANGUAGE = 223, EXTRACTOR_METATYPE_TOC = 224, - EXTRACTOR_METATYPE_LAST = 225 + + EXTRACTOR_METATYPE_VIDEO_DURATION = 225, + EXTRACTOR_METATYPE_AUDIO_DURATION = 226, + EXTRACTOR_METATYPE_SUBTITLE_DURATION = 227, + + EXTRACTOR_METATYPE_LAST = 228 }; diff --git a/src/main/extractor_metatypes.c b/src/main/extractor_metatypes.c @@ -541,6 +541,13 @@ static const struct MetaTypeDescription meta_type_descriptions[] = { { gettext_noop ("table of contents"), gettext_noop ("chapters, contents or bookmarks (in xml format)") }, /* 225 */ + { gettext_noop ("video duration"), + gettext_noop ("duration of a video stream") }, + { gettext_noop ("audio duration"), + gettext_noop ("duration of an audio stream") }, + { gettext_noop ("subtitle duration"), + gettext_noop ("duration of a subtitle stream") }, + { gettext_noop ("last"), gettext_noop ("last") } }; diff --git a/src/plugins/gstreamer_extractor.c b/src/plugins/gstreamer_extractor.c @@ -647,6 +647,7 @@ static GQuark *video_quarks; static GQuark *subtitle_quarks; +static GQuark duration_quark; static void send_streams (GstDiscovererStreamInfo *info, struct PrivStruct *ps); @@ -700,6 +701,8 @@ initialize (struct InitData *id, struct PrivStruct *ps) subtitle_quarks[0] = g_quark_from_string ("language-code"); subtitle_quarks[1] = g_quark_from_string (NULL); + duration_quark = g_quark_from_string ("duration"); + id->dc = gst_discoverer_new (timeout * GST_SECOND, &err); if (G_UNLIKELY (id->dc == NULL)) { g_print ("Error initializing: %s\n", err->message); @@ -1155,16 +1158,19 @@ send_stream_info (GstDiscovererStreamInfo * info, struct PrivStruct *ps) send_subtitle_info (GST_DISCOVERER_SUBTITLE_INFO (info), ps); else if (GST_IS_DISCOVERER_CONTAINER_INFO (info)) { + GList *child; GstDiscovererContainerInfo *c = GST_DISCOVERER_CONTAINER_INFO (info); GList *children = gst_discoverer_container_info_get_streams (c); - if (children) + for (child = children; (NULL != child) && (!ps->time_to_leave); + child = child->next) { - GstDiscovererStreamInfo *sinfo = children->data; + GstDiscovererStreamInfo *sinfo = child->data; /* send_streams () will unref it */ gst_discoverer_stream_info_ref (sinfo); send_streams (sinfo, ps); - gst_discoverer_stream_info_list_free (children); } + if (children) + gst_discoverer_stream_info_list_free (children); } } @@ -1177,9 +1183,12 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, size_t i; size_t tagl = sizeof (__known_tags) / sizeof (struct KnownTag); struct KnownTag *kt = NULL; + struct KnownTag unknown_tag = {NULL, EXTRACTOR_METATYPE_UNKNOWN}; + GValue val = { 0, }; - gchar *str; + gchar *str = NULL; + GQuark tag_quark; GstSample *sample; @@ -1194,10 +1203,12 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, break; } if (kt == NULL) - return; + kt = &unknown_tag; gst_tag_list_copy_value (&val, tags, tag); + tag_quark = g_quark_from_string (tag); + switch (G_VALUE_TYPE (&val)) { case G_TYPE_STRING: @@ -1276,6 +1287,13 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, gst_buffer_unmap (buf, &mi); } } + else if ((G_VALUE_TYPE (&val) == G_TYPE_UINT64) && + (tag_quark == duration_quark)) + { + GstClockTime duration = (GstClockTime) g_value_get_uint64 (&val); + if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0)) + str = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); + } else str = gst_value_serialize (&val); break; @@ -1338,6 +1356,19 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, break; } break; + case EXTRACTOR_METATYPE_NOMINAL_BITRATE: + switch (ps->st) + { + case STREAM_TYPE_AUDIO: + skip = TRUE; + break; + case STREAM_TYPE_VIDEO: + skip = TRUE; + break; + default: + break; + } + break; case EXTRACTOR_METATYPE_IMAGE_DIMENSIONS: switch (ps->st) { @@ -1348,6 +1379,30 @@ send_tag_foreach (const GstTagList * tags, const gchar * tag, break; } break; + case EXTRACTOR_METATYPE_DURATION: + switch (ps->st) + { + case STREAM_TYPE_VIDEO: + le_type = EXTRACTOR_METATYPE_VIDEO_DURATION; + break; + case STREAM_TYPE_AUDIO: + le_type = EXTRACTOR_METATYPE_AUDIO_DURATION; + break; + case STREAM_TYPE_SUBTITLE: + le_type = EXTRACTOR_METATYPE_SUBTITLE_DURATION; + break; + default: + break; + } + break; + case EXTRACTOR_METATYPE_UNKNOWN: + /* Convert to "key=value" form */ + { + gchar *new_str = g_strdup_printf ("%s=%s", tag, str); + g_free (str); + str = new_str; + } + break; default: break; } @@ -1501,10 +1556,9 @@ send_info (GstDiscovererInfo * info, struct PrivStruct *ps) GstClockTime duration; duration = gst_discoverer_info_get_duration (info); - if (duration > 0) + if ((GST_CLOCK_TIME_IS_VALID (duration)) && (duration > 0)) { - s = g_strdup_printf ("%" GST_TIME_FORMAT, - GST_TIME_ARGS (gst_discoverer_info_get_duration (info))); + s = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); if (s) ps->time_to_leave = ps->ec->proc (ps->ec->cls, "gstreamer", EXTRACTOR_METATYPE_DURATION, EXTRACTOR_METAFORMAT_UTF8, "text/plain", diff --git a/src/plugins/test_gstreamer.c b/src/plugins/test_gstreamer.c @@ -302,6 +302,203 @@ main (int argc, char *argv[]) }; result += (0 == ET_main ("gstreamer", ps) ? 0 : 1); } + + pre_test = discoverer_main (dc, "testdata/barsandtone.flv"); + if (pre_test != GST_DISCOVERER_MISSING_PLUGINS) + { + struct SolutionData barsandtone_sol[] = + { + { + EXTRACTOR_METATYPE_DURATION, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "0:00:06.060000000", + strlen ("0:00:06.060000000") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_MIMETYPE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "video/x-flv", + strlen ("video/x-flv") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_MIMETYPE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "video/x-vp6-flash", + strlen ("video/x-vp6-flash") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_VIDEO_DURATION, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "0:00:06.000000000", + strlen ("0:00:06.000000000") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_AUDIO_CODEC, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "MPEG-1 Layer 3 (MP3)", + strlen ("MPEG-1 Layer 3 (MP3)") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_VIDEO_CODEC, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "On2 VP6/Flash", + strlen ("On2 VP6/Flash") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_VIDEO_DIMENSIONS, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "368x288", + strlen ("368x288") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_FRAME_RATE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "10/1", + strlen ("10/1") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_PIXEL_ASPECT_RATIO, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "1/1", + strlen ("1/1") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_MIMETYPE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "audio/mpeg", + strlen ("audio/mpeg") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "mpegversion=1", + strlen ("mpegversion=1") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "mpegaudioversion=1", + strlen ("mpegaudioversion=1") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "layer=3", + strlen ("layer=3") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "parsed=true", + strlen ("parsed=true") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_AUDIO_DURATION, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "0:00:06.000000000", + strlen ("0:00:06.000000000") + 1, + 0 + }, + /* Yes, again. This seems to be a bug/feature of the element that + * gives us these streams; this doesn't happen when discovering + * Matroska files, for example. Or maybe file itself is made that way. + */ + { + EXTRACTOR_METATYPE_AUDIO_CODEC, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "MPEG-1 Layer 3 (MP3)", + strlen ("MPEG-1 Layer 3 (MP3)") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_VIDEO_CODEC, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "On2 VP6/Flash", + strlen ("On2 VP6/Flash") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "has-crc=false", + strlen ("has-crc=false") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_UNKNOWN, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "channel-mode=joint-stereo", + strlen ("channel-mode=joint-stereo") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_CHANNELS, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "2", + strlen ("2") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_SAMPLE_RATE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "44100", + strlen ("44100") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_AUDIO_BITRATE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "96000", + strlen ("96000") + 1, + 0 + }, + { 0, 0, NULL, NULL, 0, -1 } + }; + struct ProblemSet ps[] = + { + { "testdata/barsandtone.flv", + barsandtone_sol }, + { NULL, NULL } + }; + result += (0 == ET_main ("gstreamer", ps) ? 0 : 1); + } + g_object_unref (dc); return result; }