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
gstreamer_la_SOURCES = \
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_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
gstreamer_la_LIBTOOLFLAGS = --tag=disable-static

View File

@ -7,13 +7,21 @@
#define HTTP_STREAM 0
#define RTSP_STREAM 1
#include <glib.h>
#include <gst/gst.h>
#include <glib-object.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.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;
struct _Emotion_Video_Stream
@ -27,8 +35,6 @@ struct _Emotion_Video_Stream
int index;
};
typedef struct _Emotion_Audio_Stream Emotion_Audio_Stream;
struct _Emotion_Audio_Stream
{
gdouble length_time;
@ -36,8 +42,6 @@ struct _Emotion_Audio_Stream
gint samplerate;
};
typedef struct _Emotion_Gstreamer_Metadata Emotion_Gstreamer_Metadata;
struct _Emotion_Gstreamer_Metadata
{
char *title;
@ -50,9 +54,6 @@ struct _Emotion_Gstreamer_Metadata
char *disc_id;
};
typedef struct _Emotion_Gstreamer_Video Emotion_Gstreamer_Video;
struct _Emotion_Gstreamer_Video
{
/* Gstreamer elements */
@ -90,6 +91,53 @@ struct _Emotion_Gstreamer_Video
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;
#define DBG(...) EINA_LOG_DOM_DBG(_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), \
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,
Evas_Object *obj,
const char *uri);
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__ */

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 "emotion_gstreamer.h"
@ -30,32 +25,6 @@ enum {
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) \
GST_DEBUG_CATEGORY_INIT(evas_video_sink_debug, \
"emotion-sink", \
@ -71,7 +40,7 @@ GST_BOILERPLATE_FULL(EvasVideoSink,
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
evas_video_sink_base_init(gpointer g_class)
@ -93,7 +62,6 @@ evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
INF("sink init");
sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, EVAS_TYPE_VIDEO_SINK, EvasVideoSinkPrivate);
priv->o = NULL;
priv->p = ecore_pipe_add(evas_video_sink_render_handler, sink);
priv->last_buffer = NULL;
priv->width = 0;
priv->height = 0;
@ -101,7 +69,6 @@ evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
priv->eformat = EVAS_COLORSPACE_ARGB8888;
priv->data_cond = g_cond_new();
priv->buffer_mutex = g_mutex_new();
priv->preroll = EINA_FALSE;
priv->unlocked = EINA_FALSE;
}
@ -183,11 +150,6 @@ evas_video_sink_dispose(GObject* object)
priv->data_cond = 0;
}
if (priv->p) {
ecore_pipe_del(priv->p);
priv->p = NULL;
}
if (priv->last_buffer) {
gst_buffer_unref(priv->last_buffer);
priv->last_buffer = NULL;
@ -259,14 +221,7 @@ evas_video_sink_start(GstBaseSink* base_sink)
if (!priv->o)
res = FALSE;
else
{
if (!priv->p)
res = FALSE;
else
{
priv->unlocked = EINA_FALSE;
}
}
priv->unlocked = EINA_FALSE;
g_mutex_unlock(priv->buffer_mutex);
return res;
}
@ -313,27 +268,27 @@ evas_video_sink_unlock_stop(GstBaseSink* object)
static GstFlowReturn
evas_video_sink_preroll(GstBaseSink* bsink, GstBuffer* buffer)
{
GstBuffer *send;
EvasVideoSink* sink;
EvasVideoSinkPrivate* priv;
Emotion_Gstreamer_Buffer *send;
EvasVideoSinkPrivate *priv;
EvasVideoSink *sink;
sink = EVAS_VIDEO_SINK(bsink);
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;
}
static GstFlowReturn
evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
{
GstBuffer *send;
EvasVideoSink* sink;
EvasVideoSinkPrivate* priv;
Emotion_Gstreamer_Buffer *send;
EvasVideoSinkPrivate *priv;
EvasVideoSink *sink;
Eina_Bool ret;
sink = EVAS_VIDEO_SINK(bsink);
@ -347,12 +302,10 @@ evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
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);
ret = ecore_pipe_write(priv->p, &send, sizeof(buffer));
if (!ret)
return GST_FLOW_ERROR;
ecore_main_loop_thread_safe_call(evas_video_sink_main_render, send);
g_cond_wait(priv->data_cond, 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;
}
static void evas_video_sink_render_handler(void *data,
void *buf,
unsigned int len)
static void evas_video_sink_main_render(void *data)
{
Emotion_Gstreamer_Buffer *send;
Emotion_Gstreamer_Video *ev;
Emotion_Video_Stream *vstream;
EvasVideoSink* sink;
EvasVideoSinkPrivate* priv;
GstBuffer* buffer;
unsigned char *evas_data;
@ -375,14 +326,17 @@ static void evas_video_sink_render_handler(void *data,
GstFormat fmt = GST_FORMAT_TIME;
Evas_Coord w, h;
gint64 pos;
Eina_Bool preroll;
sink = (EvasVideoSink *)data;
priv = sink->priv;
send = data;
buffer = *((GstBuffer **)buf);
priv = send->sink;
if (!priv) goto exit_point;
if (priv->unlocked)
goto exit_point;
buffer = send->frame;
preroll = send->preroll;
if (priv->unlocked) goto exit_point;
gst_data = GST_BUFFER_DATA(buffer);
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_frame_resize(ev->obj, priv->width, priv->height, ev->ratio);
exit_point:
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);