mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
Manual updates and additions
Original commit message from CVS: Manual updates and additions
This commit is contained in:
parent
f5fb79c4ec
commit
7e30e55c3c
4 changed files with 451 additions and 2 deletions
|
@ -14,4 +14,195 @@
|
||||||
when a pad is created. We will use this to create our MPEG1 player.
|
when a pad is created. We will use this to create our MPEG1 player.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We'll start with a simple main function:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
#include <gnome.h>
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
void eof(GstElement *src) {
|
||||||
|
g_print("have eos, quitting\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
idle_func (gpointer data)
|
||||||
|
{
|
||||||
|
gst_bin_iterate (GST_BIN (data));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GstElement *pipeline, *src, *parse;
|
||||||
|
|
||||||
|
gst_init (&argc, &argv);
|
||||||
|
gnome_init ("MPEG1 Video player","0.0.1", argc, argv);
|
||||||
|
|
||||||
|
pipeline = gst_pipeline_new ("pipeline");
|
||||||
|
g_return_val_if_fail (pipeline != NULL, -1);
|
||||||
|
|
||||||
|
src = gst_elementfactory_make ("disksrc", "src");
|
||||||
|
g_return_val_if_fail (src != NULL, -1);
|
||||||
|
gtk_object_set (GTK_OBJECT (src), "location", argv[1], NULL);
|
||||||
|
|
||||||
|
parse = gst_elementfactory_make ("mpeg1parse", "parse");
|
||||||
|
g_return_val_if_fail (parse != NULL, -1);
|
||||||
|
|
||||||
|
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (src));
|
||||||
|
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (parse));
|
||||||
|
|
||||||
|
gtk_signal_connect (GTK_OBJECT (parse), "new_pad",
|
||||||
|
GTK_SIGNAL_FUNC (new_pad_created), pipeline);
|
||||||
|
|
||||||
|
gtk_signal_connect (GTK_OBJECT (src), "eos",
|
||||||
|
GTK_SIGNAL_FUNC (eof), NULL);
|
||||||
|
|
||||||
|
gst_pad_connect (gst_element_get_pad (src, "src"),
|
||||||
|
gst_element_get_pad (parse, "sink"));
|
||||||
|
|
||||||
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
g_idle_add (idle_func, pipeline);
|
||||||
|
|
||||||
|
gdk_threads_enter ();
|
||||||
|
gst_main ();
|
||||||
|
gdk_threads_leave ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
We create two elements: a disksrc (the element that will read the
|
||||||
|
file from disk) and an mpeg1parser. We also add an EOS (End Of Stream)
|
||||||
|
signal to the disksrc so that we will be notified when the file has ended.
|
||||||
|
There's nothing special about this piece of code except for the signal
|
||||||
|
'new_pad' that we connected to the mpeg1parser using:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
gtk_signal_connect (GTK_OBJECT (parse), "new_pad",
|
||||||
|
GTK_SIGNAL_FUNC (new_pad_created), pipeline);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
When an elementary stream has been detected in the system stream,
|
||||||
|
mpeg1parse will create a new pad that will provide the data of the
|
||||||
|
elementary stream. A function 'new_pad_created' will be called when
|
||||||
|
the pad is created:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
void
|
||||||
|
new_pad_created (GstElement *parse, GstPad *pad, GstElement *pipeline)
|
||||||
|
{
|
||||||
|
GstElement *parse_audio, *parse_video, *decode, *decode_video, *play, *videoscale, *show;
|
||||||
|
GstElement *audio_queue, *video_queue;
|
||||||
|
GstElement *audio_thread, *video_thread;
|
||||||
|
|
||||||
|
GtkWidget *appwindow;
|
||||||
|
|
||||||
|
g_print ("***** a new pad %s was created\n", gst_pad_get_name (pad));
|
||||||
|
|
||||||
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED);
|
||||||
|
|
||||||
|
// connect to audio pad
|
||||||
|
if (strncmp (gst_pad_get_name (pad), "audio_", 6) == 0) {
|
||||||
|
|
||||||
|
// construct internal pipeline elements
|
||||||
|
parse_audio = gst_elementfactory_make ("mp3parse", "parse_audio");
|
||||||
|
g_return_if_fail (parse_audio != NULL);
|
||||||
|
decode = gst_elementfactory_make ("mpg123", "decode_audio");
|
||||||
|
g_return_if_fail (decode != NULL);
|
||||||
|
play = gst_elementfactory_make ("audiosink", "play_audio");
|
||||||
|
g_return_if_fail (play != NULL);
|
||||||
|
|
||||||
|
// create the thread and pack stuff into it
|
||||||
|
audio_thread = gst_thread_new ("audio_thread");
|
||||||
|
g_return_if_fail (audio_thread != NULL);
|
||||||
|
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (parse_audio));
|
||||||
|
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (decode));
|
||||||
|
gst_bin_add (GST_BIN (audio_thread), GST_ELEMENT (play));
|
||||||
|
|
||||||
|
// set up pad connections
|
||||||
|
gst_element_add_ghost_pad (GST_ELEMENT (audio_thread),
|
||||||
|
gst_element_get_pad (parse_audio, "sink"));
|
||||||
|
gst_pad_connect (gst_element_get_pad (parse_audio,"src"),
|
||||||
|
gst_element_get_pad (decode,"sink"));
|
||||||
|
gst_pad_connect (gst_element_get_pad (decode,"src"),
|
||||||
|
gst_element_get_pad (play,"sink"));
|
||||||
|
|
||||||
|
// construct queue and connect everything in the main pipelie
|
||||||
|
audio_queue = gst_elementfactory_make ("queue", "audio_queue");
|
||||||
|
|
||||||
|
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_queue));
|
||||||
|
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (audio_thread));
|
||||||
|
|
||||||
|
gst_pad_connect (pad,
|
||||||
|
gst_element_get_pad (audio_queue, "sink"));
|
||||||
|
gst_pad_connect (gst_element_get_pad (audio_queue, "src"),
|
||||||
|
gst_element_get_pad (audio_thread, "sink"));
|
||||||
|
|
||||||
|
// set up thread state and kick things off
|
||||||
|
g_print ("setting to READY state\n");
|
||||||
|
gst_element_set_state (GST_ELEMENT (audio_thread), GST_STATE_READY);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strncmp (gst_pad_get_name (pad), "video_", 6) == 0) {
|
||||||
|
|
||||||
|
// construct internal pipeline elements
|
||||||
|
parse_video = gst_elementfactory_make ("mp1videoparse", "parse_video");
|
||||||
|
g_return_if_fail (parse_video != NULL);
|
||||||
|
decode_video = gst_elementfactory_make ("mpeg_play", "decode_video");
|
||||||
|
g_return_if_fail (decode_video != NULL);
|
||||||
|
|
||||||
|
show = gst_elementfactory_make ("videosink", "show");
|
||||||
|
g_return_if_fail (show != NULL);
|
||||||
|
|
||||||
|
appwindow = gnome_app_new ("MPEG1 player", "MPEG1 player");
|
||||||
|
gnome_app_set_contents (GNOME_APP (appwindow),
|
||||||
|
gst_util_get_widget_arg (GTK_OBJECT (show), "widget"));
|
||||||
|
gtk_widget_show_all (appwindow);
|
||||||
|
|
||||||
|
// create the thread and pack stuff into it
|
||||||
|
video_thread = gst_thread_new ("video_thread");
|
||||||
|
g_return_if_fail (video_thread != NULL);
|
||||||
|
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (parse_video));
|
||||||
|
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (decode_video));
|
||||||
|
gst_bin_add (GST_BIN (video_thread), GST_ELEMENT (show));
|
||||||
|
|
||||||
|
// set up pad connections
|
||||||
|
gst_element_add_ghost_pad (GST_ELEMENT (video_thread),
|
||||||
|
gst_element_get_pad (parse_video, "sink"));
|
||||||
|
gst_pad_connect (gst_element_get_pad (parse_video, "src"),
|
||||||
|
gst_element_get_pad (decode_video, "sink"));
|
||||||
|
gst_pad_connect (gst_element_get_pad (decode_video, "src"),
|
||||||
|
gst_element_get_pad (show, "sink"));
|
||||||
|
|
||||||
|
// construct queue and connect everything in the main pipeline
|
||||||
|
video_queue = gst_elementfactory_make ("queue", "video_queue");
|
||||||
|
|
||||||
|
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_queue));
|
||||||
|
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (video_thread));
|
||||||
|
|
||||||
|
gst_pad_connect (pad,
|
||||||
|
gst_element_get_pad (video_queue, "sink"));
|
||||||
|
gst_pad_connect (gst_element_get_pad (video_queue, "src"),
|
||||||
|
gst_element_get_pad (video_thread, "sink"));
|
||||||
|
|
||||||
|
// set up thread state and kick things off
|
||||||
|
gtk_object_set (GTK_OBJECT (video_thread), "create_thread", TRUE, NULL);
|
||||||
|
g_print ("setting to READY state\n");
|
||||||
|
gst_element_set_state (GST_ELEMENT (video_thread), GST_STATE_READY);
|
||||||
|
}
|
||||||
|
g_print("\n");
|
||||||
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
In the above example, we created new elements based on the name of
|
||||||
|
the newly created pad. We added them to a new thread There are other possibilities to check the
|
||||||
|
type of the pad, for example, by using the MIME type and the properties
|
||||||
|
of the pad.
|
||||||
|
</para>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
|
@ -102,8 +102,51 @@ video_00! (mpeg2dec ! videosink)
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>Note that the parser isn't capable of more complex pipelines yet, including
|
<para>
|
||||||
the VOB player above. The minor tweaks will be made post 0.1.0.</para>
|
Note that the parser isn't capable of more complex pipelines yet, including
|
||||||
|
the VOB player above. The minor tweaks will be made post 0.1.0.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You can also use the the parser in you own code. <application>GStreamer</application>
|
||||||
|
provides a function gst_parse_launch () that you can use to construt a pipeline.
|
||||||
|
The code of gstreamer-launch actually looks like:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GstElement *pipeline;
|
||||||
|
char **argvn;
|
||||||
|
gchar *cmdline;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
gst_init(&argc,&argv);
|
||||||
|
|
||||||
|
pipeline = gst_pipeline_new("launch");
|
||||||
|
|
||||||
|
// make a null-terminated version of argv
|
||||||
|
argvn = g_new0(char *,argc);
|
||||||
|
memcpy(argvn,argv+1,sizeof(char*)*(argc-1));
|
||||||
|
// join the argvs together
|
||||||
|
cmdline = g_strjoinv(" ",argvn);
|
||||||
|
// free the null-terminated argv
|
||||||
|
g_free(argvn);
|
||||||
|
|
||||||
|
gst_parse_launch(cmdline,pipeline);
|
||||||
|
|
||||||
|
fprintf(stderr,"RUNNING pipeline\n");
|
||||||
|
gst_element_set_state(pipeline,GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
gst_bin_iterate (GST_BIN (pipeline));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1>
|
<sect1>
|
||||||
|
|
|
@ -1,6 +1,146 @@
|
||||||
<chapter id="cha-typedetection">
|
<chapter id="cha-typedetection">
|
||||||
<title>Typedetection</title>
|
<title>Typedetection</title>
|
||||||
<para>
|
<para>
|
||||||
|
Sometimes the capabilities of a pad are not specificied. The disksrc, for
|
||||||
|
example, does not know what type of file it is reading. Before you can attach
|
||||||
|
and element to the pad of the disksrc, you need to determine the media type in
|
||||||
|
order to be able to choose a compatible element.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To solve this problem, a plugin can provide the <application>GStreamer</application>
|
||||||
|
core library with a typedefinition library with a typedefinition. The typedefinition
|
||||||
|
will contain the following information:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The MIME type we are going to define.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
An optional string with a list of possible file extensions this
|
||||||
|
type usually is associated with. the list entries are separated with
|
||||||
|
a space. eg, ".mp3 .mpa .mpg".
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
An optional typefind function.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The typefind functions give a meaning to the MIME types that are used
|
||||||
|
in GStreamer. The typefind function is a function with the following definition:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
typedef GstCaps *(*GstTypeFindFunc) (GstBuffer *buf, gpointer priv);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This typefind function will inspect a GstBuffer with data and will output
|
||||||
|
a GstCaps structure describing the type. If the typefind function does not
|
||||||
|
understand the buffer contents, it will return NULL.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<application>GStreamer</application> has a typefind element in its core elements
|
||||||
|
that can be used to determine the type of a given pad.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The next example will show how a typefind element can be inserted into a pipeline
|
||||||
|
to detect the media type of a file. It will output the capabilities of the pad into
|
||||||
|
an XML representation.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
void type_found (GstElement *typefind, GstCaps* caps);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GstElement *bin, *disksrc, *typefind;
|
||||||
|
|
||||||
|
gst_init(&argc,&argv);
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
g_print("usage: %s <filename>\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a new bin to hold the elements */
|
||||||
|
bin = gst_bin_new("bin");
|
||||||
|
g_assert(bin != NULL);
|
||||||
|
|
||||||
|
/* create a disk reader */
|
||||||
|
disksrc = gst_elementfactory_make("disksrc", "disk_source");
|
||||||
|
g_assert(disksrc != NULL);
|
||||||
|
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
|
||||||
|
|
||||||
|
/* create the typefind element */
|
||||||
|
typefind = gst_elementfactory_make("typefind", "typefind");
|
||||||
|
g_assert(typefind != NULL);
|
||||||
|
|
||||||
|
/* add objects to the main pipeline */
|
||||||
|
gst_bin_add(GST_BIN(bin), disksrc);
|
||||||
|
gst_bin_add(GST_BIN(bin), typefind);
|
||||||
|
|
||||||
|
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
|
||||||
|
type_found, NULL);
|
||||||
|
|
||||||
|
gst_pad_connect(gst_element_get_pad(disksrc,"src"),
|
||||||
|
gst_element_get_pad(typefind,"sink"));
|
||||||
|
|
||||||
|
/* start playing */
|
||||||
|
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
gst_bin_iterate(GST_BIN(bin));
|
||||||
|
|
||||||
|
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_NULL);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
We create a very simple pipeline with only a disksrc and the typefind element
|
||||||
|
in it. The sinkpad of the typefind element has been connected to the src pad
|
||||||
|
of the disksrc.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
We attached a signal 'have_type' to the typefind element which will be called
|
||||||
|
when the type of the media stream as been detected.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
the typefind function will loop over all the registered types and will execute
|
||||||
|
each of the typefind functions. As soon as a function returns a GstCaps pointer,
|
||||||
|
the type_found function will be called:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
void
|
||||||
|
type_found (GstElement *typefind, GstCaps* caps)
|
||||||
|
{
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlNodePtr parent;
|
||||||
|
|
||||||
|
doc = xmlNewDoc ("1.0");
|
||||||
|
doc->root = xmlNewDocNode (doc, NULL, "Capabilities", NULL);
|
||||||
|
|
||||||
|
parent = xmlNewChild (doc->root, NULL, "Caps1", NULL);
|
||||||
|
gst_caps_save_thyself (caps, parent);
|
||||||
|
|
||||||
|
xmlDocDump (stdout, doc);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
In the type_found function we can print or inspect the type that has been
|
||||||
|
detected using the GstCaps APIs. In this example, we just print out the
|
||||||
|
XML representation of the caps structure to stdout.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
A more usefull option would be to use the registry to look up an element
|
||||||
|
that can handle this particular caps structure, or we can also use the
|
||||||
|
autoplugger to connect this caps structure to, for example, a videosink.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
|
@ -1,6 +1,81 @@
|
||||||
<chapter id="cha-utility">
|
<chapter id="cha-utility">
|
||||||
<title>Utility functions</title>
|
<title>Utility functions</title>
|
||||||
<para>
|
<para>
|
||||||
|
while you can use the regular gtk_object_getv () function to
|
||||||
|
query the value of an object property, <application>GStreamer</application>
|
||||||
|
provides some easy wrappers for this common operation.
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
Instead of writing the following Gtk+ code to query the GTK_STRING value
|
||||||
|
of an object:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GtkArg arg;
|
||||||
|
guchar *value;
|
||||||
|
|
||||||
|
arg.name = argname;
|
||||||
|
gtk_object_getv (GTK_OBJECT (object), 1, &arg);
|
||||||
|
value = GTK_VALUE_STRING (arg);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
You can also use:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
value = gst_util_get_string_arg (object, argname);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
These convenience functions exist for the following types:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
gint: with gst_util_get_int_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
gboolean: with gst_util_get_bool_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
glong: with gst_util_get_long_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
gfloat: with gst_util_get_float_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
gdouble: with gst_util_get_double_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
guchar*: with gst_util_get_string_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
gpointer: with gst_util_get_pointer_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
GtkWidget*: with gst_util_get_widget_arg ();
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
There is also another utility function that can be used to dump a block
|
||||||
|
of memory on the console. This function is very usefull for plugin
|
||||||
|
developers. The function will dump size bytes of the memory pointed
|
||||||
|
to by mem.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
void gst_util_dump_mem(guchar *mem, guint size);
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
Loading…
Reference in a new issue