2002-11-02 13:57:18 +00:00
|
|
|
#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;
|
2002-11-10 01:27:09 +00:00
|
|
|
GstCaps *streaminfo;
|
2002-11-02 13:57:18 +00:00
|
|
|
GstCaps *caps;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2002-11-10 01:27:09 +00:00
|
|
|
print_caps (GstCaps *caps)
|
2002-11-02 13:57:18 +00:00
|
|
|
{
|
2002-11-10 01:27:09 +00:00
|
|
|
if (caps == NULL) return;
|
2002-11-09 18:40:35 +00:00
|
|
|
if (!strcmp (gst_caps_get_mime (caps), "application/x-gst-metadata") ||
|
2002-11-10 01:27:09 +00:00
|
|
|
!strcmp (gst_caps_get_mime (caps), "application/x-gst-streaminfo"))
|
2002-11-09 18:40:35 +00:00
|
|
|
{
|
2002-11-02 13:57:18 +00:00
|
|
|
GstProps *props = caps->properties;
|
2002-11-10 01:27:09 +00:00
|
|
|
GList *walk;
|
|
|
|
/* ugly hack, but ok for now. If needed, fix by individual strcmp */
|
|
|
|
g_print (" %s:\n", gst_caps_get_mime (caps) + 18);
|
|
|
|
if (props == NULL) {
|
|
|
|
g_print (" none\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
walk = props->properties;
|
2002-11-02 13:57:18 +00:00
|
|
|
|
|
|
|
while (walk) {
|
|
|
|
GstPropsEntry *entry = (GstPropsEntry *) walk->data;
|
|
|
|
const gchar *name;
|
|
|
|
const gchar *str_val;
|
|
|
|
gint int_val;
|
|
|
|
GstPropsType type;
|
|
|
|
|
|
|
|
name = gst_props_entry_get_name (entry);
|
2003-03-24 02:58:13 +00:00
|
|
|
type = gst_props_entry_get_props_type (entry);
|
2002-11-02 13:57:18 +00:00
|
|
|
switch (type) {
|
|
|
|
case GST_PROPS_STRING_TYPE:
|
|
|
|
gst_props_entry_get_string (entry, &str_val);
|
|
|
|
g_print (" %s='%s'\n", name, str_val);
|
|
|
|
break;
|
|
|
|
case GST_PROPS_INT_TYPE:
|
|
|
|
gst_props_entry_get_int (entry, &int_val);
|
|
|
|
g_print (" %s=%d\n", name, int_val);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
walk = g_list_next (walk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2002-11-10 01:27:09 +00:00
|
|
|
g_print (" unkown caps type\n");
|
2002-11-02 13:57:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_format (GstCaps *caps)
|
|
|
|
{
|
|
|
|
g_print (" format:\n");
|
|
|
|
if (!caps || caps->properties == NULL) {
|
|
|
|
g_print (" unkown\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!strcmp (gst_caps_get_mime (caps), "audio/raw")) {
|
|
|
|
gint channels;
|
|
|
|
gint rate;
|
|
|
|
|
|
|
|
gst_caps_get_int (caps, "channels", &channels);
|
|
|
|
gst_caps_get_int (caps, "rate", &rate);
|
|
|
|
|
|
|
|
g_print (" channels: %d\n", channels);
|
|
|
|
g_print (" rate: %d\n", rate);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
g_print (" unkown format\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_lbs_info (struct probe_context *context, gint stream)
|
|
|
|
{
|
|
|
|
const GstFormat *formats;
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-10 01:27:09 +00:00
|
|
|
/* FIXME: need a better name here */
|
2002-11-02 13:57:18 +00:00
|
|
|
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;
|
|
|
|
|
2002-11-27 20:49:11 +00:00
|
|
|
format = *formats;
|
|
|
|
formats++;
|
|
|
|
|
|
|
|
if (format == context->ls_format) {
|
2002-11-02 13:57:18 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2002-11-27 20:49:11 +00:00
|
|
|
definition = gst_format_get_details (format);
|
2002-11-02 13:57:18 +00:00
|
|
|
|
|
|
|
/* get start and end position of this stream */
|
2003-01-10 10:22:25 +00:00
|
|
|
res = gst_pad_convert (context->pad,
|
2002-11-02 13:57:18 +00:00
|
|
|
context->ls_format, stream,
|
|
|
|
&format, &value_start);
|
2003-01-10 10:22:25 +00:00
|
|
|
res &= gst_pad_convert (context->pad,
|
2002-11-02 13:57:18 +00:00
|
|
|
context->ls_format, stream + 1,
|
|
|
|
&format, &value_end);
|
|
|
|
|
|
|
|
if (res) {
|
|
|
|
/* substract to get the length */
|
|
|
|
value_end -= value_start;
|
|
|
|
|
2002-11-27 20:49:11 +00:00
|
|
|
if (format == GST_FORMAT_TIME) {
|
2002-11-02 13:57:18 +00:00
|
|
|
value_end /= (GST_SECOND/100);
|
2003-01-10 10:22:25 +00:00
|
|
|
g_print (" %s: %lld:%02lld.%02lld\n", definition->nick,
|
2002-11-02 13:57:18 +00:00
|
|
|
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")) {
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-02 13:57:18 +00:00
|
|
|
g_value_init (&value, pspec->value_type);
|
|
|
|
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
|
|
|
context->metadata = g_value_peek_pointer (&value);
|
|
|
|
}
|
2002-11-10 01:27:09 +00:00
|
|
|
else if (!strcmp (pspec->name, "streaminfo")) {
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-09 18:40:35 +00:00
|
|
|
g_value_init (&value, pspec->value_type);
|
|
|
|
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
2002-11-10 01:27:09 +00:00
|
|
|
context->streaminfo = g_value_peek_pointer (&value);
|
2002-11-09 18:40:35 +00:00
|
|
|
} else if (!strcmp (pspec->name, "caps")) {
|
2002-11-02 13:57:18 +00:00
|
|
|
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;
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-02 13:57:18 +00:00
|
|
|
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;
|
|
|
|
}
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-10 01:27:09 +00:00
|
|
|
print_caps (context->metadata);
|
|
|
|
print_caps (context->streaminfo);
|
2002-11-02 13:57:18 +00:00
|
|
|
print_format (context->caps);
|
|
|
|
print_lbs_info (context, stream);
|
|
|
|
|
|
|
|
g_print ("\n");
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-02 13:57:18 +00:00
|
|
|
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;
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-02 13:57:18 +00:00
|
|
|
format = *formats;
|
2002-11-27 20:49:11 +00:00
|
|
|
formats++;
|
2002-11-02 13:57:18 +00:00
|
|
|
|
2003-01-10 10:22:25 +00:00
|
|
|
res = gst_pad_query (context->pad, GST_QUERY_TOTAL,
|
2002-11-02 13:57:18 +00:00
|
|
|
&format, &value);
|
|
|
|
|
2002-11-27 20:49:11 +00:00
|
|
|
definition = gst_format_get_details (format);
|
2002-11-02 13:57:18 +00:00
|
|
|
|
|
|
|
if (res) {
|
|
|
|
if (format == GST_FORMAT_TIME) {
|
|
|
|
value /= (GST_SECOND/100);
|
2003-01-10 10:22:25 +00:00
|
|
|
g_print (" total %s: %lld:%02lld.%02lld\n", definition->nick,
|
2002-11-02 13:57:18 +00:00
|
|
|
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;
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-02 13:57:18 +00:00
|
|
|
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");
|
2002-11-27 20:49:11 +00:00
|
|
|
//vorbisfile = gst_element_factory_make ("mad", "vorbisfile");
|
2002-11-02 13:57:18 +00:00
|
|
|
g_assert (vorbisfile);
|
|
|
|
|
|
|
|
gst_bin_add (GST_BIN (pipeline), filesrc);
|
|
|
|
gst_bin_add (GST_BIN (pipeline), vorbisfile);
|
|
|
|
|
2003-01-10 10:22:25 +00:00
|
|
|
gst_element_link_pads (filesrc, "src", vorbisfile, "sink");
|
2002-11-02 13:57:18 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2003-01-10 10:22:25 +00:00
|
|
|
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
2002-11-02 13:57:18 +00:00
|
|
|
G_CALLBACK (deep_notify), context);
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-02 13:57:18 +00:00
|
|
|
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++;
|
|
|
|
}
|
2003-01-10 10:22:25 +00:00
|
|
|
|
2002-11-02 13:57:18 +00:00
|
|
|
/* stop probe */
|
|
|
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|