Ecore: ecore_pipe documentation.

SVN revision: 60878
This commit is contained in:
Jonas M. Gastal 2011-06-30 18:10:30 +00:00
parent 4ecb2fccad
commit df2d739a35
5 changed files with 321 additions and 190 deletions

View File

@ -508,3 +508,68 @@
* Shows how to use fd handlers.
*/
/**
* @page tutorial_ecore_pipe_gstreamer_example
*
* Here is an example that uses the pipe wrapper with a Gstreamer
* pipeline. For each decoded frame in the Gstreamer thread, a handle
* is called in the ecore thread.
*
* @include ecore_pipe_gstreamer_example.c
* @example ecore_pipe_gstreamer_example.c
*/
/**
* @page tutorial_ecore_pipe_simple_example
* @dontinclude ecore_pipe_simple_example.c
*
* This example shows some simple usage of ecore_pipe. We are going to create a
* pipe, fork our process, and then the child is going to comunicate to the
* parent the result of its processing through the pipe.
*
* As always we start with our includes, nothing especial:
* @skip #include
* @until Ecore.h
*
* The first thing we are going to define in our example is the function we are
* going to run on the child process, which, as mentioned, will do some
* processing and then will write the result to the pipe:
* @until }
* @until }
* @note The sleep was added so the parent process would think the child process
* was doing something interesting...
*
* Next up is our function for handling data arriving in the pipe. It copies the
* data to another buffer, adds a terminating NULL and prints it. Also if it
* receives a certain string it stops the main loop(efectvely ending the
* program):
* @until }
* @until }
*
* And now on to our main function, we start by declaring some variables and
* initializing ecore:
* @until ecore_init
*
* And since we are talking about pipes let's create one:
* @until pipe_add
*
* Now we are going to fork:
* @until fork
* @note duh...
*
* The child process is going to do the our fancy processing:
* @until }
* @note It's very important to call ecore_pipe_read_close() here so that the
* child process won't read what it is writing to the pipe itself.
*
* And the parent is going to run ecore's main loop waiting for some data:
* @until }
* @note Calling ecore_pipe_write_close() here isn't important but since we
* aren't going to write in the pipe it is good practice.
*
* And finally when done processing(the child) or done receiving(the parent) we
* delete the pipe and shutdown ecore:
* @until }
*
* @example ecore_pipe_simple_example.c
*/

View File

@ -24,7 +24,9 @@ SRCS = \
ecore_con_client_example.c \
ecore_con_server_example.c \
ecore_fd_handler_gnutls_example.c \
ecore_file_download_example.c
ecore_file_download_example.c \
ecore_pipe_simple_example.c \
ecore_pipe_gstreamer_example.c
EXTRA_DIST = $(SRCS)
@ -43,6 +45,7 @@ pkglib_PROGRAMS += \
ecore_idler_example \
ecore_job_example \
ecore_timer_example \
ecore_time_functions_example
ecore_time_functions_example \
ecore_pipe_simple_example
endif

View File

@ -0,0 +1,180 @@
#include <gst/gst.h>
#include <Ecore.h>
static int nbr = 0;
static GstElement *_buid_pipeline (gchar *filename, Ecore_Pipe *pipe);
static void new_decoded_pad_cb (GstElement *demuxer,
GstPad *new_pad,
gpointer user_data);
static void handler(void *data, void *buf, unsigned int len)
{
GstBuffer *buffer = *((GstBuffer **)buf);
printf ("handler : %p\n", buffer);
printf ("frame : %d %p %lld %p\n", nbr++, data, (long long)GST_BUFFER_DURATION(buffer), buffer);
gst_buffer_unref (buffer);
}
static void handoff (GstElement* object,
GstBuffer* arg0,
GstPad* arg1,
gpointer user_data)
{
Ecore_Pipe *pipe;
pipe = (Ecore_Pipe *)user_data;
printf ("handoff : %p\n", arg0);
gst_buffer_ref (arg0);
ecore_pipe_write(pipe, &arg0, sizeof(arg0));
}
int
main (int argc, char *argv[])
{
GstElement *pipeline;
char *filename;
Ecore_Pipe *pipe;
gst_init (&argc, &argv);
if (!ecore_init ())
{
gst_deinit ();
return 0;
}
pipe = ecore_pipe_add (handler);
if (!pipe)
{
ecore_shutdown ();
gst_deinit ();
return 0;
}
if (argc < 2) {
g_print ("usage: %s file.avi\n", argv[0]);
ecore_pipe_del (pipe);
ecore_shutdown ();
gst_deinit ();
return 0;
}
filename = argv[1];
pipeline = _buid_pipeline (filename, pipe);
if (!pipeline) {
g_print ("Error during the pipeline building\n");
ecore_pipe_del (pipe);
ecore_shutdown ();
gst_deinit ();
return -1;
}
gst_element_set_state (pipeline, GST_STATE_PLAYING);
ecore_main_loop_begin();
ecore_pipe_del (pipe);
ecore_shutdown ();
gst_deinit ();
return 0;
}
static void
new_decoded_pad_cb (GstElement *demuxer,
GstPad *new_pad,
gpointer user_data)
{
GstElement *decoder;
GstPad *pad;
GstCaps *caps;
gchar *str;
caps = gst_pad_get_caps (new_pad);
str = gst_caps_to_string (caps);
if (g_str_has_prefix (str, "video/")) {
decoder = GST_ELEMENT (user_data);
pad = gst_element_get_pad (decoder, "sink");
if (GST_PAD_LINK_FAILED (gst_pad_link (new_pad, pad))) {
g_warning ("Failed to link %s:%s to %s:%s", GST_DEBUG_PAD_NAME (new_pad),
GST_DEBUG_PAD_NAME (pad));
}
}
g_free (str);
gst_caps_unref (caps);
}
static GstElement
_buid_pipeline (gchar *filename, Ecore_Pipe *pipe)
{
GstElement *pipeline;
GstElement *filesrc;
GstElement *demuxer;
GstElement *decoder;
GstElement *sink;
GstStateChangeReturn res;
pipeline = gst_pipeline_new ("pipeline");
if (!pipeline)
return NULL;
filesrc = gst_element_factory_make ("filesrc", "filesrc");
if (!filesrc) {
printf ("no filesrc");
goto failure;
}
g_object_set (G_OBJECT (filesrc), "location", filename, NULL);
demuxer = gst_element_factory_make ("oggdemux", "demuxer");
if (!demuxer) {
printf ("no demux");
goto failure;
}
decoder = gst_element_factory_make ("theoradec", "decoder");
if (!decoder) {
printf ("no dec");
goto failure;
}
g_signal_connect (demuxer, "pad-added",
G_CALLBACK (new_decoded_pad_cb), decoder);
sink = gst_element_factory_make ("fakesink", "sink");
if (!sink) {
printf ("no sink");
goto failure;
}
g_object_set (G_OBJECT (sink), "sync", EINA_TRUE, NULL);
g_object_set (G_OBJECT (sink), "signal-handoffs", EINA_TRUE, NULL);
g_signal_connect (sink, "handoff",
G_CALLBACK (handoff), pipe);
gst_bin_add_many (GST_BIN (pipeline),
filesrc, demuxer, decoder, sink, NULL);
if (!gst_element_link (filesrc, demuxer))
goto failure;
if (!gst_element_link (decoder, sink))
goto failure;
res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
if (res == GST_STATE_CHANGE_FAILURE)
goto failure;
res = gst_element_get_state( pipeline, NULL, NULL, GST_CLOCK_TIME_NONE );
if (res != GST_STATE_CHANGE_SUCCESS)
goto failure;
return pipeline;
failure:
gst_object_unref (GST_OBJECT (pipeline));
return NULL;
}

View File

@ -0,0 +1,66 @@
//Compile with:
//gcc -g -Wall `pkg-config --cflags --libs ecore` -o ecore_pipe_simple_example ecore_pipe_simple_example.c
#include <unistd.h>
#include <Ecore.h>
static void
do_lengthy_task(Ecore_Pipe *pipe)
{
int i, j;
char *buffer;
for (i = 0; i < 20; i++)
{
sleep(1);
buffer = malloc(sizeof(char) * i);
for (j = 0; j < i; j++)
buffer[j] = 'a' + j;
ecore_pipe_write(pipe, buffer, i);
free(buffer);
}
ecore_pipe_write(pipe, "close", 5);
}
static void
handler(void *data, void *buf, unsigned int len)
{
char *str = malloc(sizeof(char) * len + 1);
memcpy(str, buf, len);
str[len] = '\0';
printf("received %d bytes\n", len);
printf("content: %s\n", (const char*)str);
free(str);
if (len && !strncmp(buf, "close", len < 5 ? len : 5))
{
printf("close requested\n");
ecore_main_loop_quit();
}
}
int
main (int argc, char *argv[])
{
Ecore_Pipe *pipe;
pid_t child_pid;
ecore_init();
pipe = ecore_pipe_add(handler, NULL);
child_pid = fork();
if(!child_pid)
{
ecore_pipe_read_close(pipe);
do_lengthy_task(pipe);
}
else
{
ecore_pipe_write_close(pipe);
ecore_main_loop_begin();
}
ecore_pipe_del(pipe);
ecore_shutdown();
return 0;
}

View File

@ -98,9 +98,8 @@ static Eina_Bool _ecore_pipe_read(void *data, Ecore_Fd_Handler *fd_handler);
/**
* @addtogroup Ecore_Pipe_Group Pipe wrapper
*
* These functions wrap the pipe / write / read functions to
* easily integrate a loop that is in its own thread to the ecore
* main loop.
* These functions wrap the pipe / write / read functions to easily integrate
* its use into ecore's main loop.
*
* The ecore_pipe_add() function creates file descriptors (sockets on
* Windows) and attach an handle to the ecore main loop. That handle is
@ -108,191 +107,9 @@ static Eina_Bool _ecore_pipe_read(void *data, Ecore_Fd_Handler *fd_handler);
* just call ecore_pipe_write(). When you are done, just call
* ecore_pipe_del().
*
* Here is an example that uses the pipe wrapper with a Gstreamer
* pipeline. For each decoded frame in the Gstreamer thread, a handle
* is called in the ecore thread.
*
* @code#include <gst/gst.h>
* #include <Ecore.h>
*
* static int nbr = 0;
*
* static GstElement *_buid_pipeline (gchar *filename, Ecore_Pipe *pipe);
*
* static void new_decoded_pad_cb (GstElement *demuxer,
* GstPad *new_pad,
* gpointer user_data);
*
* static void handler(void *data, void *buf, unsigned int len)
* {
* GstBuffer *buffer = *((GstBuffer **)buf);
*
* printf ("handler : %p\n", buffer);
* printf ("frame : %d %p %lld %p\n", nbr++, data, (long long)GST_BUFFER_DURATION(buffer), buffer);
* gst_buffer_unref (buffer);
* }
*
*
* static void handoff (GstElement* object,
* GstBuffer* arg0,
* GstPad* arg1,
* gpointer user_data)
* {
* Ecore_Pipe *pipe;
*
* pipe = (Ecore_Pipe *)user_data;
* printf ("handoff : %p\n", arg0);
* gst_buffer_ref (arg0);
* ecore_pipe_write(pipe, &arg0, sizeof(arg0));
* }
*
* int
* main (int argc, char *argv[])
* {
* GstElement *pipeline;
* char *filename;
* Ecore_Pipe *pipe;
*
* gst_init (&argc, &argv);
*
* if (!ecore_init ())
* {
* gst_deinit ();
* return 0;
* }
*
* pipe = ecore_pipe_add (handler);
* if (!pipe)
* {
* ecore_shutdown ();
* gst_deinit ();
* return 0;
* }
*
* if (argc < 2) {
* g_print ("usage: %s file.avi\n", argv[0]);
* ecore_pipe_del (pipe);
* ecore_shutdown ();
* gst_deinit ();
* return 0;
* }
* filename = argv[1];
*
* pipeline = _buid_pipeline (filename, pipe);
* if (!pipeline) {
* g_print ("Error during the pipeline building\n");
* ecore_pipe_del (pipe);
* ecore_shutdown ();
* gst_deinit ();
* return -1;
* }
*
* gst_element_set_state (pipeline, GST_STATE_PLAYING);
*
* ecore_main_loop_begin();
*
* ecore_pipe_del (pipe);
* ecore_shutdown ();
* gst_deinit ();
*
* return 0;
* }
*
* static void
* new_decoded_pad_cb (GstElement *demuxer,
* GstPad *new_pad,
* gpointer user_data)
* {
* GstElement *decoder;
* GstPad *pad;
* GstCaps *caps;
* gchar *str;
*
* caps = gst_pad_get_caps (new_pad);
* str = gst_caps_to_string (caps);
*
* if (g_str_has_prefix (str, "video/")) {
* decoder = GST_ELEMENT (user_data);
*
* pad = gst_element_get_pad (decoder, "sink");
* if (GST_PAD_LINK_FAILED (gst_pad_link (new_pad, pad))) {
* g_warning ("Failed to link %s:%s to %s:%s", GST_DEBUG_PAD_NAME (new_pad),
* GST_DEBUG_PAD_NAME (pad));
* }
* }
* g_free (str);
* gst_caps_unref (caps);
* }
*
* static GstElement *
* _buid_pipeline (gchar *filename, Ecore_Pipe *pipe)
* {
* GstElement *pipeline;
* GstElement *filesrc;
* GstElement *demuxer;
* GstElement *decoder;
* GstElement *sink;
GstStateChangeReturn res;
*
* pipeline = gst_pipeline_new ("pipeline");
* if (!pipeline)
* return NULL;
*
* filesrc = gst_element_factory_make ("filesrc", "filesrc");
* if (!filesrc) {
* printf ("no filesrc");
* goto failure;
* }
* g_object_set (G_OBJECT (filesrc), "location", filename, NULL);
*
* demuxer = gst_element_factory_make ("oggdemux", "demuxer");
* if (!demuxer) {
* printf ("no demux");
* goto failure;
* }
*
* decoder = gst_element_factory_make ("theoradec", "decoder");
* if (!decoder) {
* printf ("no dec");
* goto failure;
* }
*
* g_signal_connect (demuxer, "pad-added",
* G_CALLBACK (new_decoded_pad_cb), decoder);
*
* sink = gst_element_factory_make ("fakesink", "sink");
* if (!sink) {
* printf ("no sink");
* goto failure;
* }
* g_object_set (G_OBJECT (sink), "sync", EINA_TRUE, NULL);
* g_object_set (G_OBJECT (sink), "signal-handoffs", EINA_TRUE, NULL);
* g_signal_connect (sink, "handoff",
* G_CALLBACK (handoff), pipe);
*
* gst_bin_add_many (GST_BIN (pipeline),
* filesrc, demuxer, decoder, sink, NULL);
*
* if (!gst_element_link (filesrc, demuxer))
* goto failure;
* if (!gst_element_link (decoder, sink))
* goto failure;
*
* res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
* if (res == GST_STATE_CHANGE_FAILURE)
* goto failure;
*
* res = gst_element_get_state( pipeline, NULL, NULL, GST_CLOCK_TIME_NONE );
* if (res != GST_STATE_CHANGE_SUCCESS)
* goto failure;
*
* return pipeline;
*
* failure:
* gst_object_unref (GST_OBJECT (pipeline));
* return NULL;
* }
* @endcode
* For examples see here:
* @li @ref tutorial_ecore_pipe_gstreamer_example
* @li @ref tutorial_ecore_pipe_simple_example
*/