mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +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.
|
||||
</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>
|
||||
|
|
|
@ -102,8 +102,51 @@ video_00! (mpeg2dec ! videosink)
|
|||
|
||||
</para>
|
||||
|
||||
<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>
|
||||
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>
|
||||
|
|
|
@ -1,6 +1,146 @@
|
|||
<chapter id="cha-typedetection">
|
||||
<title>Typedetection</title>
|
||||
<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>
|
||||
|
||||
</chapter>
|
||||
|
|
|
@ -1,6 +1,81 @@
|
|||
<chapter id="cha-utility">
|
||||
<title>Utility functions</title>
|
||||
<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>
|
||||
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>
|
||||
|
|
Loading…
Reference in a new issue