* 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
+ */
\ No newline at end of file
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)
ecore_idler_example \
ecore_job_example \
ecore_timer_example \
- ecore_time_functions_example
+ ecore_time_functions_example \
+ ecore_pipe_simple_example
endif
--- /dev/null
+#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;
+}
--- /dev/null
+//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;
+}
/**
* @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
* 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
*/