#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
int index;
};
-typedef struct _Emotion_Audio_Stream Emotion_Audio_Stream;
-
struct _Emotion_Audio_Stream
{
gdouble length_time;
gint samplerate;
};
-typedef struct _Emotion_Gstreamer_Metadata Emotion_Gstreamer_Metadata;
-
struct _Emotion_Gstreamer_Metadata
{
char *title;
char *disc_id;
};
-
-typedef struct _Emotion_Gstreamer_Video Emotion_Gstreamer_Video;
-
struct _Emotion_Gstreamer_Video
{
/* Gstreamer elements */
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__)
(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__ */
-#include <glib.h>
-#include <gst/gst.h>
-#include <gst/video/video.h>
-#include <gst/video/gstvideosink.h>
-
#include <Ecore.h>
#include "emotion_gstreamer.h"
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", \
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)
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;
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;
}
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;
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;
}
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);
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);
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;
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;
_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);
+
+ exit_point:
+ emotion_gstreamer_buffer_free(send);
- if (priv->preroll) return ;
+ if (preroll) return ;
g_mutex_lock(priv->buffer_mutex);