emotion: remove g stuff and make it safer.

SVN revision: 62514
This commit is contained in:
Cedric BAIL 2011-08-16 16:11:50 +00:00
parent 1ca5e18738
commit 6245940483
4 changed files with 138 additions and 76 deletions

View File

@ -14,12 +14,16 @@ emotion_gstreamer_buffer_alloc(EvasVideoSinkPrivate *sink,
{
Emotion_Gstreamer_Buffer *send;
if (!sink->ev) return NULL;
send = malloc(sizeof (Emotion_Gstreamer_Buffer));
if (!send) return NULL;
send->sink = sink;
send->frame = gst_buffer_ref(buffer);
send->preroll = preroll;
sink->ev->out++;
send->ev = sink->ev;
return send;
}
@ -27,6 +31,13 @@ emotion_gstreamer_buffer_alloc(EvasVideoSinkPrivate *sink,
void
emotion_gstreamer_buffer_free(Emotion_Gstreamer_Buffer *send)
{
send->ev->in++;
if (send->ev->in == send->ev->out
&& send->ev->threads == NULL
&& send->ev->delete_me)
em_shutdown(send->ev);
gst_buffer_unref(send->frame);
free(send);
}
@ -37,6 +48,8 @@ emotion_gstreamer_message_alloc(Emotion_Gstreamer_Video *ev,
{
Emotion_Gstreamer_Message *send;
if (!ev) return NULL;
send = malloc(sizeof (Emotion_Gstreamer_Message));
if (!send) return NULL;
@ -52,7 +65,9 @@ emotion_gstreamer_message_free(Emotion_Gstreamer_Message *send)
{
send->ev->in++;
if (send->ev->in == send->ev->out && send->ev->delete_me)
if (send->ev->in == send->ev->out
&& send->ev->threads == NULL
&& send->ev->delete_me)
em_shutdown(send->ev);
gst_message_unref(send->msg);

View File

@ -333,6 +333,7 @@ em_init(Evas_Object *obj,
ev->volume = 0.8;
ev->play_started = 0;
ev->delete_me = EINA_FALSE;
ev->threads = NULL;
*emotion_video = ev;
@ -355,10 +356,15 @@ em_shutdown(void *video)
if (!ev)
return 0;
if (ev->thread)
if (ev->threads)
{
ecore_thread_cancel(ev->thread);
ev->thread = NULL;
Ecore_Thread *t;
EINA_LIST_FREE(ev->threads, t)
ecore_thread_cancel(t);
ev->delete_me = EINA_TRUE;
return 1;
}
if (ev->in != ev->out)
@ -375,9 +381,12 @@ em_shutdown(void *video)
if (ev->pipeline)
{
g_object_set(G_OBJECT(ev->sink), "ev", NULL, NULL);
g_object_set(G_OBJECT(ev->sink), "evas-object", NULL, NULL);
gst_element_set_state(ev->pipeline, GST_STATE_NULL);
gst_object_unref(ev->pipeline);
ev->pipeline = NULL;
ev->sink = NULL;
}
EINA_LIST_FREE(ev->audio_streams, astream)
@ -470,17 +479,22 @@ em_file_close(void *video)
ev->eos_bus = NULL;
}
if (ev->thread)
if (ev->threads)
{
ecore_thread_cancel(ev->thread);
ev->thread = NULL;
Ecore_Thread *t;
EINA_LIST_FREE(ev->threads, t)
ecore_thread_cancel(t);
}
if (ev->pipeline)
{
g_object_set(G_OBJECT(ev->sink), "ev", NULL, NULL);
g_object_set(G_OBJECT(ev->sink), "evas-object", NULL, NULL);
gst_element_set_state(ev->pipeline, GST_STATE_NULL);
gst_object_unref(ev->pipeline);
ev->pipeline = NULL;
ev->sink = NULL;
}
/* we clear the stream lists */
@ -521,7 +535,7 @@ em_stop(void *video)
ev = (Emotion_Gstreamer_Video *)video;
if (!ev->pipeline) return ;
gst_element_set_state(ev->pipeline, GST_STATE_PAUSED);
ev->play = 0;
}
@ -1478,7 +1492,7 @@ _eos_sync_fct(GstBus *bus, GstMessage *msg, gpointer data)
case GST_MESSAGE_ASYNC_DONE:
send = emotion_gstreamer_message_alloc(ev, msg);
if (send) ecore_main_loop_thread_safe_call(_eos_main_fct, send);
if (send) ecore_main_loop_thread_safe_call_async(_eos_main_fct, send);
break;
@ -1504,13 +1518,15 @@ _emotion_gstreamer_video_pipeline_parse(Emotion_Gstreamer_Video *ev,
if (ev->pipeline_parsed)
return EINA_TRUE;
if (force && ev->thread)
if (force && ev->threads)
{
ecore_thread_cancel(ev->thread);
ev->thread = NULL;
Ecore_Thread *t;
EINA_LIST_FREE(ev->threads, t)
ecore_thread_cancel(t);
}
if (ev->thread)
if (ev->threads)
return EINA_FALSE;
res = gst_element_get_state(ev->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);

View File

@ -59,7 +59,8 @@ struct _Emotion_Gstreamer_Video
{
/* Gstreamer elements */
GstElement *pipeline;
Ecore_Thread *thread;
GstElement *sink;
Eina_List *threads;
/* eos */
GstBus *eos_bus;
@ -113,13 +114,15 @@ struct _EvasVideoSinkPrivate {
Evas_Object *o;
Emotion_Gstreamer_Video *ev;
int width;
int height;
Evas_Colorspace eformat;
GstVideoFormat gformat;
GMutex* buffer_mutex;
GCond* data_cond;
Eina_Lock m;
Eina_Condition c;
/* We need to keep a copy of the last inserted buffer as evas doesn't copy YUV data around */
GstBuffer *last_buffer;
@ -137,6 +140,7 @@ struct _EvasVideoSinkPrivate {
struct _Emotion_Gstreamer_Buffer
{
Emotion_Gstreamer_Video *ev;
EvasVideoSinkPrivate *sink;
GstBuffer *frame;

View File

@ -20,7 +20,8 @@ enum {
PROP_EVAS_OBJECT,
PROP_WIDTH,
PROP_HEIGHT,
PROP_LAST,
PROP_EV,
PROP_LAST
};
static guint evas_video_sink_signals[LAST_SIGNAL] = { 0, };
@ -67,13 +68,25 @@ evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
priv->height = 0;
priv->gformat = GST_VIDEO_FORMAT_UNKNOWN;
priv->eformat = EVAS_COLORSPACE_ARGB8888;
priv->data_cond = g_cond_new();
priv->buffer_mutex = g_mutex_new();
eina_lock_new(&priv->m);
eina_condition_new(&priv->c, &priv->m);
priv->unlocked = EINA_FALSE;
}
/**** Object methods ****/
static void
_cleanup_priv(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
{
EvasVideoSinkPrivate* priv;
priv = data;
eina_lock_take(&priv->m);
if (priv->o == obj)
priv->o = NULL;
eina_lock_release(&priv->m);
}
static void
evas_video_sink_set_property(GObject * object, guint prop_id,
@ -87,9 +100,16 @@ evas_video_sink_set_property(GObject * object, guint prop_id,
switch (prop_id) {
case PROP_EVAS_OBJECT:
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
evas_object_event_callback_del(priv->o, EVAS_CALLBACK_FREE, _cleanup_priv);
priv->o = g_value_get_pointer (value);
g_mutex_unlock(priv->buffer_mutex);
evas_object_event_callback_add(priv->o, EVAS_CALLBACK_FREE, _cleanup_priv, priv);
eina_lock_release(&priv->m);
break;
case PROP_EV:
eina_lock_take(&priv->m);
priv->ev = g_value_get_pointer (value);
eina_lock_release(&priv->m);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -110,19 +130,24 @@ evas_video_sink_get_property(GObject * object, guint prop_id,
switch (prop_id) {
case PROP_EVAS_OBJECT:
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
g_value_set_pointer (value, priv->o);
g_mutex_unlock(priv->buffer_mutex);
eina_lock_release(&priv->m);
break;
case PROP_WIDTH:
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
g_value_set_int(value, priv->width);
g_mutex_unlock(priv->buffer_mutex);
eina_lock_release(&priv->m);
break;
case PROP_HEIGHT:
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
g_value_set_int (value, priv->height);
g_mutex_unlock(priv->buffer_mutex);
eina_lock_release(&priv->m);
break;
case PROP_EV:
eina_lock_take(&priv->m);
g_value_set_pointer (value, priv->ev);
eina_lock_release(&priv->m);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -140,15 +165,8 @@ evas_video_sink_dispose(GObject* object)
sink = EVAS_VIDEO_SINK(object);
priv = sink->priv;
if (priv->buffer_mutex) {
g_mutex_free(priv->buffer_mutex);
priv->buffer_mutex = 0;
}
if (priv->data_cond) {
g_cond_free(priv->data_cond);
priv->data_cond = 0;
}
eina_lock_free(&priv->m);
eina_condition_free(&priv->c);
if (priv->last_buffer) {
gst_buffer_unref(priv->last_buffer);
@ -217,12 +235,12 @@ evas_video_sink_start(GstBaseSink* base_sink)
gboolean res = TRUE;
priv = EVAS_VIDEO_SINK(base_sink)->priv;
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
if (!priv->o)
res = FALSE;
else
priv->unlocked = EINA_FALSE;
g_mutex_unlock(priv->buffer_mutex);
eina_lock_release(&priv->m);
return res;
}
@ -257,9 +275,9 @@ evas_video_sink_unlock_stop(GstBaseSink* object)
sink = EVAS_VIDEO_SINK(object);
priv = sink->priv;
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
priv->unlocked = FALSE;
g_mutex_unlock(priv->buffer_mutex);
eina_lock_release(&priv->m);
return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop,
(object), TRUE);
@ -278,7 +296,7 @@ evas_video_sink_preroll(GstBaseSink* bsink, GstBuffer* buffer)
send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_TRUE);
if (send)
ecore_main_loop_thread_safe_call(evas_video_sink_main_render, send);
ecore_main_loop_thread_safe_call_async(evas_video_sink_main_render, send);
return GST_FLOW_OK;
}
@ -289,40 +307,42 @@ evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
Emotion_Gstreamer_Buffer *send;
EvasVideoSinkPrivate *priv;
EvasVideoSink *sink;
Eina_Bool ret;
sink = EVAS_VIDEO_SINK(bsink);
priv = sink->priv;
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
if (priv->unlocked) {
ERR("LOCKED");
g_mutex_unlock(priv->buffer_mutex);
eina_lock_release(&priv->m);
return GST_FLOW_OK;
}
send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_FALSE);
if (!send) return GST_FLOW_ERROR;
if (!send) {
eina_lock_release(&priv->m);
return GST_FLOW_ERROR;
}
ecore_main_loop_thread_safe_call(evas_video_sink_main_render, send);
ecore_main_loop_thread_safe_call_async(evas_video_sink_main_render, send);
g_cond_wait(priv->data_cond, priv->buffer_mutex);
g_mutex_unlock(priv->buffer_mutex);
eina_condition_wait(&priv->c);
eina_lock_release(&priv->m);
return GST_FLOW_OK;
}
static void evas_video_sink_main_render(void *data)
static void
evas_video_sink_main_render(void *data)
{
Emotion_Gstreamer_Buffer *send;
Emotion_Gstreamer_Video *ev;
Emotion_Gstreamer_Video *ev = NULL;
Emotion_Video_Stream *vstream;
EvasVideoSinkPrivate* priv;
GstBuffer* buffer;
unsigned char *evas_data;
const guint8 *gst_data;
GstQuery *query;
GstFormat fmt = GST_FORMAT_TIME;
Evas_Coord w, h;
gint64 pos;
@ -332,6 +352,7 @@ static void evas_video_sink_main_render(void *data)
priv = send->sink;
if (!priv) goto exit_point;
if (!priv->o) goto exit_point;
buffer = send->frame;
preroll = send->preroll;
@ -341,7 +362,7 @@ static void evas_video_sink_main_render(void *data)
gst_data = GST_BUFFER_DATA(buffer);
if (!gst_data) goto exit_point;
ev = evas_object_data_get(priv->o, "_emotion_gstreamer_video");
ev = send->ev;
if (!ev) goto exit_point;
_emotion_gstreamer_video_pipeline_parse(ev, EINA_TRUE);
@ -514,27 +535,23 @@ static void evas_video_sink_main_render(void *data)
exit_point:
emotion_gstreamer_buffer_free(send);
if (preroll) return ;
if (preroll || !priv->o || !ev) return ;
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
if (!priv->unlocked)
eina_condition_signal(&priv->c);
if (priv->unlocked) {
g_mutex_unlock(priv->buffer_mutex);
return;
}
g_cond_signal(priv->data_cond);
g_mutex_unlock(priv->buffer_mutex);
eina_lock_release(&priv->m);
}
static void
unlock_buffer_mutex(EvasVideoSinkPrivate* priv)
{
g_mutex_lock(priv->buffer_mutex);
eina_lock_take(&priv->m);
priv->unlocked = EINA_TRUE;
g_cond_signal(priv->data_cond);
g_mutex_unlock(priv->buffer_mutex);
eina_condition_signal(&priv->c);
eina_lock_release(&priv->m);
}
static void
@ -591,6 +608,10 @@ evas_video_sink_class_init(EvasVideoSinkClass* klass)
g_param_spec_int ("height", "Height",
"The height of the video",
0, 65536, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_EV,
g_param_spec_pointer ("ev", "Emotion_Gstreamer_Video",
"THe internal data of the emotion object",
G_PARAM_READWRITE));
gobject_class->dispose = evas_video_sink_dispose;
@ -622,19 +643,24 @@ gstreamer_plugin_init (GstPlugin * plugin)
}
static void
_emotion_gstreamer_pause(void *data, Ecore_Thread *thread __UNUSED__)
_emotion_gstreamer_pause(void *data, Ecore_Thread *thread)
{
Emotion_Gstreamer_Video *ev = data;
if (ecore_thread_check(thread) || !ev->pipeline) return ;
gst_element_set_state(ev->pipeline, GST_STATE_PAUSED);
}
static void
_emotion_gstreamer_cancel(void *data, Ecore_Thread *thread __UNUSED__)
_emotion_gstreamer_cancel(void *data, Ecore_Thread *thread)
{
Emotion_Gstreamer_Video *ev = data;
ev->thread = NULL;
ev->threads = eina_list_remove(ev->threads, thread);
if (ev->in == ev->out && ev->threads == NULL && ev->delete_me)
em_shutdown(ev);
}
static void
@ -652,7 +678,6 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
GstElement *playbin;
GstElement *sink;
Evas_Object *obj;
GstStateChangeReturn res;
obj = emotion_object_image_get(o);
if (!obj)
@ -675,22 +700,24 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
goto unref_pipeline;
}
g_object_set(G_OBJECT(sink), "evas-object", obj, NULL);
g_object_set(G_OBJECT(sink), "ev", ev, NULL);
g_object_set(G_OBJECT(playbin), "video-sink", sink, NULL);
g_object_set(G_OBJECT(playbin), "uri", uri, NULL);
g_object_set(G_OBJECT(sink), "evas-object", obj, NULL);
ev->pipeline = playbin;
ev->thread = ecore_thread_run(_emotion_gstreamer_pause,
_emotion_gstreamer_end,
_emotion_gstreamer_cancel,
ev);
ev->sink = sink;
ev->threads = eina_list_append(ev->threads,
ecore_thread_run(_emotion_gstreamer_pause,
_emotion_gstreamer_end,
_emotion_gstreamer_cancel,
ev));
/** NOTE: you need to set: GST_DEBUG_DUMP_DOT_DIR=/tmp EMOTION_ENGINE=gstreamer to save the $EMOTION_GSTREAMER_DOT file in '/tmp' */
/** then call dot -Tpng -oemotion_pipeline.png /tmp/$TIMESTAMP-$EMOTION_GSTREAMER_DOT.dot */
if (getenv("EMOTION_GSTREAMER_DOT")) GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(playbin), GST_DEBUG_GRAPH_SHOW_ALL, getenv("EMOTION_GSTREAMER_DOT"));
evas_object_data_set(obj, "_emotion_gstreamer_video", ev);
return playbin;
unref_pipeline: