forked from enlightenment/efl
parent
4ecb2fccad
commit
df2d739a35
|
@ -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
|
||||
*/
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue