emotion: use new ecore infrastructure and remove some race condition.

SVN revision: 61949
This commit is contained in:
Cedric BAIL 2011-08-01 12:21:14 +00:00
parent d0e8b833a9
commit ecadef9ee9
3 changed files with 91 additions and 97 deletions

View File

@ -19,7 +19,8 @@ pkgdir = $(libdir)/emotion
pkg_LTLIBRARIES = gstreamer.la pkg_LTLIBRARIES = gstreamer.la
gstreamer_la_SOURCES = \ gstreamer_la_SOURCES = \
emotion_gstreamer.c \ emotion_gstreamer.c \
emotion_sink.c emotion_sink.c \
emotion_alloc.c
gstreamer_la_LIBADD = @GSTREAMER_LIBS@ $(top_builddir)/src/lib/libemotion.la gstreamer_la_LIBADD = @GSTREAMER_LIBS@ $(top_builddir)/src/lib/libemotion.la
gstreamer_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version gstreamer_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
gstreamer_la_LIBTOOLFLAGS = --tag=disable-static gstreamer_la_LIBTOOLFLAGS = --tag=disable-static

View File

@ -7,13 +7,21 @@
#define HTTP_STREAM 0 #define HTTP_STREAM 0
#define RTSP_STREAM 1 #define RTSP_STREAM 1
#include <glib.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <glib-object.h> #include <glib-object.h>
#include <gst/video/gstvideosink.h> #include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include "emotion_private.h" #include "emotion_private.h"
typedef struct _EvasVideoSinkPrivate EvasVideoSinkPrivate;
typedef struct _EvasVideoSink EvasVideoSink;
typedef struct _EvasVideoSinkClass EvasVideoSinkClass;
typedef struct _Emotion_Gstreamer_Video Emotion_Gstreamer_Video;
typedef struct _Emotion_Audio_Stream Emotion_Audio_Stream;
typedef struct _Emotion_Gstreamer_Metadata Emotion_Gstreamer_Metadata;
typedef struct _Emotion_Gstreamer_Buffer Emotion_Gstreamer_Buffer;
typedef struct _Emotion_Video_Stream Emotion_Video_Stream; typedef struct _Emotion_Video_Stream Emotion_Video_Stream;
struct _Emotion_Video_Stream struct _Emotion_Video_Stream
@ -27,8 +35,6 @@ struct _Emotion_Video_Stream
int index; int index;
}; };
typedef struct _Emotion_Audio_Stream Emotion_Audio_Stream;
struct _Emotion_Audio_Stream struct _Emotion_Audio_Stream
{ {
gdouble length_time; gdouble length_time;
@ -36,8 +42,6 @@ struct _Emotion_Audio_Stream
gint samplerate; gint samplerate;
}; };
typedef struct _Emotion_Gstreamer_Metadata Emotion_Gstreamer_Metadata;
struct _Emotion_Gstreamer_Metadata struct _Emotion_Gstreamer_Metadata
{ {
char *title; char *title;
@ -50,9 +54,6 @@ struct _Emotion_Gstreamer_Metadata
char *disc_id; char *disc_id;
}; };
typedef struct _Emotion_Gstreamer_Video Emotion_Gstreamer_Video;
struct _Emotion_Gstreamer_Video struct _Emotion_Gstreamer_Video
{ {
/* Gstreamer elements */ /* Gstreamer elements */
@ -90,6 +91,53 @@ struct _Emotion_Gstreamer_Video
unsigned char audio_mute : 1; unsigned char audio_mute : 1;
}; };
struct _EvasVideoSink {
/*< private >*/
GstVideoSink parent;
EvasVideoSinkPrivate *priv;
};
struct _EvasVideoSinkClass {
/*< private >*/
GstVideoSinkClass parent_class;
};
struct _EvasVideoSinkPrivate {
EINA_REFCOUNT;
Evas_Object *o;
int width;
int height;
Evas_Colorspace eformat;
GstVideoFormat gformat;
GMutex* buffer_mutex;
GCond* data_cond;
/* We need to keep a copy of the last inserted buffer as evas doesn't copy YUV data around */
GstBuffer *last_buffer;
// If this is TRUE all processing should finish ASAP
// This is necessary because there could be a race between
// unlock() and render(), where unlock() wins, signals the
// GCond, then render() tries to render a frame although
// everything else isn't running anymore. This will lead
// to deadlocks because render() holds the stream lock.
//
// Protected by the buffer mutex
Eina_Bool unlocked : 1;
};
struct _Emotion_Gstreamer_Buffer
{
EvasVideoSinkPrivate *sink;
GstBuffer *frame;
Eina_Bool preroll : 1;
};
extern int _emotion_gstreamer_log_domain; extern int _emotion_gstreamer_log_domain;
#define DBG(...) EINA_LOG_DOM_DBG(_emotion_gstreamer_log_domain, __VA_ARGS__) #define DBG(...) EINA_LOG_DOM_DBG(_emotion_gstreamer_log_domain, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(_emotion_gstreamer_log_domain, __VA_ARGS__) #define INF(...) EINA_LOG_DOM_INFO(_emotion_gstreamer_log_domain, __VA_ARGS__)
@ -119,25 +167,14 @@ extern int _emotion_gstreamer_log_domain;
(G_TYPE_INSTANCE_GET_CLASS((obj), \ (G_TYPE_INSTANCE_GET_CLASS((obj), \
EVAS_TYPE_VIDEO_SINK, EvasVideoSinkClass)) EVAS_TYPE_VIDEO_SINK, EvasVideoSinkClass))
typedef struct _EvasVideoSink EvasVideoSink;
typedef struct _EvasVideoSinkClass EvasVideoSinkClass;
typedef struct _EvasVideoSinkPrivate EvasVideoSinkPrivate;
struct _EvasVideoSink {
/*< private >*/
GstVideoSink parent;
EvasVideoSinkPrivate *priv;
};
struct _EvasVideoSinkClass {
/*< private >*/
GstVideoSinkClass parent_class;
};
GstElement *gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev, GstElement *gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
Evas_Object *obj, Evas_Object *obj,
const char *uri); const char *uri);
gboolean gstreamer_plugin_init(GstPlugin *plugin); gboolean gstreamer_plugin_init(GstPlugin *plugin);
Emotion_Gstreamer_Buffer *emotion_gstreamer_buffer_alloc(EvasVideoSinkPrivate *sink,
GstBuffer *buffer,
Eina_Bool preroll);
void emotion_gstreamer_buffer_free(Emotion_Gstreamer_Buffer *send);
#endif /* __EMOTION_GSTREAMER_H__ */ #endif /* __EMOTION_GSTREAMER_H__ */

View File

@ -1,8 +1,3 @@
#include <glib.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideosink.h>
#include <Ecore.h> #include <Ecore.h>
#include "emotion_gstreamer.h" #include "emotion_gstreamer.h"
@ -30,32 +25,6 @@ enum {
static guint evas_video_sink_signals[LAST_SIGNAL] = { 0, }; static guint evas_video_sink_signals[LAST_SIGNAL] = { 0, };
struct _EvasVideoSinkPrivate {
Evas_Object *o;
Ecore_Pipe *p;
int width;
int height;
Evas_Colorspace eformat;
GstVideoFormat gformat;
GMutex* buffer_mutex;
GCond* data_cond;
GstBuffer *last_buffer; /* We need to keep a copy of the last inserted buffer as evas doesn't copy YUV data around */
// If this is TRUE all processing should finish ASAP
// This is necessary because there could be a race between
// unlock() and render(), where unlock() wins, signals the
// GCond, then render() tries to render a frame although
// everything else isn't running anymore. This will lead
// to deadlocks because render() holds the stream lock.
//
// Protected by the buffer mutex
Eina_Bool unlocked : 1;
Eina_Bool preroll : 1;
};
#define _do_init(bla) \ #define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT(evas_video_sink_debug, \ GST_DEBUG_CATEGORY_INIT(evas_video_sink_debug, \
"emotion-sink", \ "emotion-sink", \
@ -71,7 +40,7 @@ GST_BOILERPLATE_FULL(EvasVideoSink,
static void unlock_buffer_mutex(EvasVideoSinkPrivate* priv); static void unlock_buffer_mutex(EvasVideoSinkPrivate* priv);
static void evas_video_sink_render_handler(void *data, void *buf, unsigned int len); static void evas_video_sink_main_render(void *data);
static void static void
evas_video_sink_base_init(gpointer g_class) evas_video_sink_base_init(gpointer g_class)
@ -93,7 +62,6 @@ evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
INF("sink init"); INF("sink init");
sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, EVAS_TYPE_VIDEO_SINK, EvasVideoSinkPrivate); sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, EVAS_TYPE_VIDEO_SINK, EvasVideoSinkPrivate);
priv->o = NULL; priv->o = NULL;
priv->p = ecore_pipe_add(evas_video_sink_render_handler, sink);
priv->last_buffer = NULL; priv->last_buffer = NULL;
priv->width = 0; priv->width = 0;
priv->height = 0; priv->height = 0;
@ -101,7 +69,6 @@ evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
priv->eformat = EVAS_COLORSPACE_ARGB8888; priv->eformat = EVAS_COLORSPACE_ARGB8888;
priv->data_cond = g_cond_new(); priv->data_cond = g_cond_new();
priv->buffer_mutex = g_mutex_new(); priv->buffer_mutex = g_mutex_new();
priv->preroll = EINA_FALSE;
priv->unlocked = EINA_FALSE; priv->unlocked = EINA_FALSE;
} }
@ -183,11 +150,6 @@ evas_video_sink_dispose(GObject* object)
priv->data_cond = 0; priv->data_cond = 0;
} }
if (priv->p) {
ecore_pipe_del(priv->p);
priv->p = NULL;
}
if (priv->last_buffer) { if (priv->last_buffer) {
gst_buffer_unref(priv->last_buffer); gst_buffer_unref(priv->last_buffer);
priv->last_buffer = NULL; priv->last_buffer = NULL;
@ -259,14 +221,7 @@ evas_video_sink_start(GstBaseSink* base_sink)
if (!priv->o) if (!priv->o)
res = FALSE; res = FALSE;
else else
{ priv->unlocked = EINA_FALSE;
if (!priv->p)
res = FALSE;
else
{
priv->unlocked = EINA_FALSE;
}
}
g_mutex_unlock(priv->buffer_mutex); g_mutex_unlock(priv->buffer_mutex);
return res; return res;
} }
@ -313,27 +268,27 @@ evas_video_sink_unlock_stop(GstBaseSink* object)
static GstFlowReturn static GstFlowReturn
evas_video_sink_preroll(GstBaseSink* bsink, GstBuffer* buffer) evas_video_sink_preroll(GstBaseSink* bsink, GstBuffer* buffer)
{ {
GstBuffer *send; Emotion_Gstreamer_Buffer *send;
EvasVideoSink* sink; EvasVideoSinkPrivate *priv;
EvasVideoSinkPrivate* priv; EvasVideoSink *sink;
sink = EVAS_VIDEO_SINK(bsink); sink = EVAS_VIDEO_SINK(bsink);
priv = sink->priv; priv = sink->priv;
send = gst_buffer_ref(buffer); send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_TRUE);
priv->preroll = EINA_TRUE; if (send)
ecore_main_loop_thread_safe_call(evas_video_sink_main_render, send);
ecore_pipe_write(priv->p, &send, sizeof(buffer));
return GST_FLOW_OK; return GST_FLOW_OK;
} }
static GstFlowReturn static GstFlowReturn
evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
{ {
GstBuffer *send; Emotion_Gstreamer_Buffer *send;
EvasVideoSink* sink; EvasVideoSinkPrivate *priv;
EvasVideoSinkPrivate* priv; EvasVideoSink *sink;
Eina_Bool ret; Eina_Bool ret;
sink = EVAS_VIDEO_SINK(bsink); sink = EVAS_VIDEO_SINK(bsink);
@ -347,12 +302,10 @@ evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
priv->preroll = EINA_FALSE; send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_FALSE);
if (!send) return GST_FLOW_ERROR;
send = gst_buffer_ref(buffer); ecore_main_loop_thread_safe_call(evas_video_sink_main_render, send);
ret = ecore_pipe_write(priv->p, &send, sizeof(buffer));
if (!ret)
return GST_FLOW_ERROR;
g_cond_wait(priv->data_cond, priv->buffer_mutex); g_cond_wait(priv->data_cond, priv->buffer_mutex);
g_mutex_unlock(priv->buffer_mutex); g_mutex_unlock(priv->buffer_mutex);
@ -360,13 +313,11 @@ evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
static void evas_video_sink_render_handler(void *data, static void evas_video_sink_main_render(void *data)
void *buf,
unsigned int len)
{ {
Emotion_Gstreamer_Buffer *send;
Emotion_Gstreamer_Video *ev; Emotion_Gstreamer_Video *ev;
Emotion_Video_Stream *vstream; Emotion_Video_Stream *vstream;
EvasVideoSink* sink;
EvasVideoSinkPrivate* priv; EvasVideoSinkPrivate* priv;
GstBuffer* buffer; GstBuffer* buffer;
unsigned char *evas_data; unsigned char *evas_data;
@ -375,14 +326,17 @@ static void evas_video_sink_render_handler(void *data,
GstFormat fmt = GST_FORMAT_TIME; GstFormat fmt = GST_FORMAT_TIME;
Evas_Coord w, h; Evas_Coord w, h;
gint64 pos; gint64 pos;
Eina_Bool preroll;
sink = (EvasVideoSink *)data; send = data;
priv = sink->priv;
buffer = *((GstBuffer **)buf); priv = send->sink;
if (!priv) goto exit_point;
if (priv->unlocked) buffer = send->frame;
goto exit_point; preroll = send->preroll;
if (priv->unlocked) goto exit_point;
gst_data = GST_BUFFER_DATA(buffer); gst_data = GST_BUFFER_DATA(buffer);
if (!gst_data) goto exit_point; if (!gst_data) goto exit_point;
@ -552,11 +506,13 @@ static void evas_video_sink_render_handler(void *data,
_emotion_video_pos_update(ev->obj, ev->position, vstream->length_time); _emotion_video_pos_update(ev->obj, ev->position, vstream->length_time);
_emotion_frame_resize(ev->obj, priv->width, priv->height, ev->ratio); _emotion_frame_resize(ev->obj, priv->width, priv->height, ev->ratio);
exit_point:
if (priv->last_buffer) gst_buffer_unref(priv->last_buffer); if (priv->last_buffer) gst_buffer_unref(priv->last_buffer);
priv->last_buffer = buffer; priv->last_buffer = gst_buffer_ref(buffer);
if (priv->preroll) return ; exit_point:
emotion_gstreamer_buffer_free(send);
if (preroll) return ;
g_mutex_lock(priv->buffer_mutex); g_mutex_lock(priv->buffer_mutex);