| #include <stdlib.h> |
| #include <gst/gst.h> |
| #include <string.h> |
| |
| static gboolean ready = FALSE; |
| |
| struct probe_context |
| { |
| GstElement *pipeline; |
| GstElement *element; |
| GstPad *pad; |
| GstFormat ls_format; |
| |
| gint total_ls; |
| |
| GstCaps *metadata; |
| GstCaps *streaminfo; |
| GstCaps *caps; |
| }; |
| |
| static void |
| print_caps (GstCaps * caps) |
| { |
| char *s; |
| |
| s = gst_caps_to_string (caps); |
| g_print (" %s\n", s); |
| g_free (s); |
| } |
| |
| static void |
| print_format (GstCaps * caps) |
| { |
| char *s; |
| |
| s = gst_caps_to_string (caps); |
| g_print (" format: %s\n", s); |
| g_free (s); |
| } |
| |
| static void |
| print_lbs_info (struct probe_context *context, gint stream) |
| { |
| const GstFormat *formats; |
| |
| /* FIXME: need a better name here */ |
| g_print (" stream info:\n"); |
| |
| /* report info in all supported formats */ |
| formats = gst_pad_get_formats (context->pad); |
| while (*formats) { |
| const GstFormatDefinition *definition; |
| gint64 value_start, value_end; |
| gboolean res; |
| GstFormat format; |
| |
| format = *formats; |
| formats++; |
| |
| if (format == context->ls_format) { |
| continue; |
| } |
| |
| definition = gst_format_get_details (format); |
| |
| /* get start and end position of this stream */ |
| res = gst_pad_convert (context->pad, |
| context->ls_format, stream, &format, &value_start); |
| res &= gst_pad_convert (context->pad, |
| context->ls_format, stream + 1, &format, &value_end); |
| |
| if (res) { |
| /* substract to get the length */ |
| value_end -= value_start; |
| |
| if (format == GST_FORMAT_TIME) { |
| value_end /= (GST_SECOND / 100); |
| g_print (" %s: %lld:%02lld.%02lld\n", definition->nick, |
| value_end / 6000, (value_end / 100) % 60, (value_end % 100)); |
| } else { |
| g_print (" %s: %lld\n", definition->nick, value_end); |
| } |
| } else |
| g_print (" could not get logical stream %s\n", definition->nick); |
| |
| } |
| } |
| |
| static void |
| deep_notify (GObject * object, GstObject * origin, |
| GParamSpec * pspec, gpointer data) |
| { |
| struct probe_context *context = (struct probe_context *) data; |
| GValue value = { 0, }; |
| |
| if (!strcmp (pspec->name, "metadata")) { |
| |
| g_value_init (&value, pspec->value_type); |
| g_object_get_property (G_OBJECT (origin), pspec->name, &value); |
| context->metadata = g_value_peek_pointer (&value); |
| } else if (!strcmp (pspec->name, "streaminfo")) { |
| |
| g_value_init (&value, pspec->value_type); |
| g_object_get_property (G_OBJECT (origin), pspec->name, &value); |
| context->streaminfo = g_value_peek_pointer (&value); |
| } else if (!strcmp (pspec->name, "caps")) { |
| if (GST_IS_PAD (origin) && GST_PAD (origin) == context->pad) { |
| g_value_init (&value, pspec->value_type); |
| g_object_get_property (G_OBJECT (origin), pspec->name, &value); |
| context->caps = g_value_peek_pointer (&value); |
| |
| ready = TRUE; |
| } |
| } |
| } |
| |
| static gboolean |
| collect_logical_stream_properties (struct probe_context *context, gint stream) |
| { |
| GstEvent *event; |
| gboolean res; |
| gint count; |
| |
| g_print ("info for logical stream %d:\n", stream); |
| |
| /* seek to stream */ |
| event = gst_event_new_seek (context->ls_format | |
| GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, stream); |
| res = gst_pad_send_event (context->pad, event); |
| if (!res) { |
| g_warning ("seek to logical track failed"); |
| return FALSE; |
| } |
| |
| /* run the pipeline to get the info */ |
| count = 0; |
| ready = FALSE; |
| while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready) { |
| count++; |
| if (count > 10) |
| break; |
| } |
| |
| print_caps (context->metadata); |
| print_caps (context->streaminfo); |
| print_format (context->caps); |
| print_lbs_info (context, stream); |
| |
| g_print ("\n"); |
| |
| return TRUE; |
| } |
| |
| static void |
| collect_stream_properties (struct probe_context *context) |
| { |
| const GstFormat *formats; |
| |
| ready = FALSE; |
| while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready); |
| |
| g_print ("stream info:\n"); |
| |
| context->total_ls = -1; |
| |
| /* report info in all supported formats */ |
| formats = gst_pad_get_formats (context->pad); |
| while (*formats) { |
| const GstFormatDefinition *definition; |
| gint64 value; |
| gboolean res; |
| GstFormat format; |
| |
| format = *formats; |
| formats++; |
| |
| res = gst_pad_query (context->pad, GST_QUERY_TOTAL, &format, &value); |
| |
| definition = gst_format_get_details (format); |
| |
| if (res) { |
| if (format == GST_FORMAT_TIME) { |
| value /= (GST_SECOND / 100); |
| g_print (" total %s: %lld:%02lld.%02lld\n", definition->nick, |
| value / 6000, (value / 100) % 60, (value % 100)); |
| } else { |
| if (format == context->ls_format) |
| context->total_ls = value; |
| g_print (" total %s: %lld\n", definition->nick, value); |
| } |
| } |
| } |
| |
| if (context->total_ls == -1) { |
| g_warning (" could not get number of logical streams"); |
| } |
| g_print ("\n"); |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| GstElement *pipeline; |
| GstElement *filesrc; |
| GstElement *vorbisfile; |
| GstPad *pad; |
| GstFormat logical_stream_format; |
| struct probe_context *context; |
| gint stream; |
| |
| gst_init (&argc, &argv); |
| |
| if (argc < 2) { |
| g_print ("usage: %s <oggfile>\n", argv[0]); |
| return (-1); |
| } |
| |
| pipeline = gst_pipeline_new ("pipeline"); |
| |
| filesrc = gst_element_factory_make ("filesrc", "filesrc"); |
| g_assert (filesrc); |
| g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); |
| |
| vorbisfile = gst_element_factory_make ("vorbisfile", "vorbisfile"); |
| //vorbisfile = gst_element_factory_make ("mad", "vorbisfile"); |
| g_assert (vorbisfile); |
| |
| gst_bin_add (GST_BIN (pipeline), filesrc); |
| gst_bin_add (GST_BIN (pipeline), vorbisfile); |
| |
| gst_element_link_pads (filesrc, "src", vorbisfile, "sink"); |
| |
| pad = gst_element_get_pad (vorbisfile, "src"); |
| g_assert (pad); |
| |
| logical_stream_format = gst_format_get_by_nick ("logical_stream"); |
| g_assert (logical_stream_format != 0); |
| |
| context = g_new0 (struct probe_context, 1); |
| context->pipeline = pipeline; |
| context->element = vorbisfile; |
| context->pad = pad; |
| context->ls_format = logical_stream_format; |
| |
| g_signal_connect (G_OBJECT (pipeline), "deep_notify", |
| G_CALLBACK (deep_notify), context); |
| |
| gst_element_set_state (pipeline, GST_STATE_PLAYING); |
| |
| /* at this point we can inspect the stream */ |
| collect_stream_properties (context); |
| |
| /* loop over all logical streams to get info */ |
| stream = 0; |
| while (stream < context->total_ls) { |
| collect_logical_stream_properties (context, stream); |
| stream++; |
| } |
| |
| /* stop probe */ |
| gst_element_set_state (pipeline, GST_STATE_NULL); |
| |
| return 0; |
| } |