[cogl/wip/cogl-gst: 16/27] cogl-gst: Upgrade cogl-gst to gstreamer-1.0
- From: Neil Roberts <nroberts src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [cogl/wip/cogl-gst: 16/27] cogl-gst: Upgrade cogl-gst to gstreamer-1.0
- Date: Wed, 6 Mar 2013 18:53:45 +0000 (UTC)
commit a76d4d78832118acbeb6624d1c3affb1407462c3
Author: Plamena Manolova <plamena n manolova intel com>
Date: Thu Feb 28 18:14:54 2013 +0000
cogl-gst: Upgrade cogl-gst to gstreamer-1.0
Upgrades cogl-gst to gstreamer-1.0 and gets rid
of the cogl-gst-video-player utility. Implements
cogl-gst-video-sink-new, but keeps plugin
registered for user convinience.
cogl-gst/Makefile.am | 30 ++-
cogl-gst/cogl-gst-video-player.c | 273 -------------
cogl-gst/cogl-gst-video-player.h | 121 ------
cogl-gst/cogl-gst-video-sink.c | 772 ++++++++++++++++++++++--------------
cogl-gst/cogl-gst-video-sink.h | 4 +
configure.ac | 12 +-
examples/cogl-basic-video-player.c | 43 ++-
7 files changed, 546 insertions(+), 709 deletions(-)
---
diff --git a/cogl-gst/Makefile.am b/cogl-gst/Makefile.am
index 316656e..d2afa93 100644
--- a/cogl-gst/Makefile.am
+++ b/cogl-gst/Makefile.am
@@ -9,13 +9,12 @@ EXTRA_DIST =
source_c = \
cogl-gst-shader.c \
- cogl-gst-video-player.c \
cogl-gst-video-sink.c \
$(NULL)
source_h = \
cogl-gst.h \
- cogl-gst-video-player.h \
+ cogl-gst-shader.h \
cogl-gst-video-sink.h \
$(NULL)
@@ -32,7 +31,8 @@ libcogl_gst_la_LDFLAGS = \
-export-dynamic \
-export-symbols-regex "^cogl_gst_.*" \
-no-undefined \
- -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@
+ -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@ \
+ -rpath $(libdir)
AM_CPPFLAGS = \
-DCOGL_COMPILATION \
@@ -43,9 +43,31 @@ AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir)
-cogl_gstheadersdir = $(includedir)/cogl/cogl-gst
+cogl_gstheadersdir = $(includedir)/cogl2/cogl-gst
cogl_gstheaders_HEADERS = $(source_h)
+plugin_source_c = \
+ $(srcdir)/cogl-gst.h \
+ $(srcdir)/cogl-gst-shader.c \
+ $(srcdir)/cogl-gst-shader.h \
+ $(srcdir)/cogl-gst-video-sink.c \
+ $(srcdir)/cogl-gst-video-sink.h \
+ $(NULL)
+
+libgstcogl_la_SOURCES = \
+ $(plugin_source_c) \
+ $(NULL)
+
+plugin_LTLIBRARIES = libgstcogl.la
+
+libgstcogl_la_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_GST_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
+libgstcogl_la_LIBADD = $(top_builddir)/cogl/libcogl2.la
+libgstcogl_la_LIBADD += $(COGL_DEP_LIBS) $(COGL_GST_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
+libgstcogl_la_LDFLAGS = \
+ -avoid-version -no-undefined \
+ $(NULL)
+
+
pc_files = cogl-gst.pc
pkgconfigdir = $(libdir)/pkgconfig
diff --git a/cogl-gst/cogl-gst-video-sink.c b/cogl-gst/cogl-gst-video-sink.c
index 5bbd651..52ce311 100644
--- a/cogl-gst/cogl-gst-video-sink.c
+++ b/cogl-gst/cogl-gst-video-sink.c
@@ -47,27 +47,32 @@
#define COGL_GST_TEXTURE_FLAGS \
(COGL_TEXTURE_NO_SLICING | COGL_TEXTURE_NO_ATLAS)
-#define PACKAGE "GStreamer"
-#define VERSION "0.10"
+#define PACKAGE "CoglGst"
+#define VERSION "0.0"
#define COGL_GST_DEFAULT_PRIORITY (G_PRIORITY_HIGH_IDLE)
+#ifdef HAVE_HW_DECODER_SUPPORT
+#define GST_USE_UNSTABLE_API 1
+#include <gst/video/gstsurfacemeta.h>
+#endif
+
+#define BASE_SINK_CAPS "{ AYUV," \
+ "YV12," \
+ "I420," \
+ "RGBA," \
+ "BGRA," \
+ "RGB," \
+ "BGR }"
+
+
+#define SINK_CAPS GST_VIDEO_CAPS_MAKE(BASE_SINK_CAPS)
+
+static GstStaticPadTemplate sinktemplate_all = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (SINK_CAPS));
-static GstStaticPadTemplate sinktemplate_all =
- GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" \
- GST_VIDEO_CAPS_YUV ("YV12") ";" \
- GST_VIDEO_CAPS_YUV ("I420") ";" \
- GST_VIDEO_CAPS_RGBA ";" \
- GST_VIDEO_CAPS_BGRA ";" \
- GST_VIDEO_CAPS_RGB ";" \
- GST_VIDEO_CAPS_BGR));
-
-static GstElementDetails cogl_gst_video_sink_details =
- GST_ELEMENT_DETAILS ("Cogl video sink", "Sink/Video",
- "Sends video data from a GStreamer pipeline to a Cogl pipeline",
- "Jonathan Matthew <jonathan kaolin wh9 net>, "
- "Matthew Allum <mallum o-hand com, "
- "Chris Lord <chris o-hand com>, "
- "Plamena Manolova <plamena n manolova intel com>");
+#define cogl_gst_video_sink_parent_class parent_class
+G_DEFINE_TYPE (CoglGstVideoSink, cogl_gst_video_sink, GST_TYPE_BASE_SINK);
enum
{
@@ -82,7 +87,8 @@ typedef enum
COGL_GST_RGB24,
COGL_GST_AYUV,
COGL_GST_YV12,
- COGL_GST_I420,
+ COGL_GST_SURFACE,
+ COGL_GST_I420
}CoglGstVideoFormat;
typedef enum
@@ -96,6 +102,7 @@ typedef struct _CoglGstSource
CoglGstVideoSink *sink;
GMutex buffer_lock;
GstBuffer *buffer;
+ CoglBool has_new_caps;
}CoglGstSource;
typedef void (CoglGstRendererPaint) (CoglGstVideoSink*);
@@ -109,45 +116,31 @@ typedef struct _CoglGstRenderer
GstStaticCaps caps;
void (*init) (CoglGstVideoSink *sink);
void (*deinit) (CoglGstVideoSink *sink);
- void (*upload) (CoglGstVideoSink *sink,
- GstBuffer *buffer);
+ CoglBool (*upload) (CoglGstVideoSink *sink,
+ GstBuffer *buffer);
}CoglGstRenderer;
-typedef enum _CoglGstRendererState
-{
- COGL_GST_RENDERER_STOPPED,
- COGL_GST_RENDERER_RUNNING,
- COGL_GST_RENDERER_NEED_GC,
-}CoglGstRendererState;
-
struct _CoglGstVideoSinkPrivate
{
CoglContext *ctx;
CoglPipeline *pipeline;
CoglGstVideoFormat format;
CoglBool bgr;
- int width;
- int height;
- int fps_n, fps_d;
- int par_n, par_d;
- int free_layer;
CoglGstSource *source;
GSList *renderers;
GstCaps *caps;
CoglGstRenderer *renderer;
- CoglGstRendererState renderer_state;
GMainContext *g_ctx;
GMainLoop *loop;
CoglSnippetHook hook;
+ GstFlowReturn flow_return;
+ int free_layer;
+ GstVideoInfo info;
+ #ifdef HAVE_HW_DECODER_SUPPORT
+ GstSurfaceConverter *converter;
+ #endif
};
-
-GST_BOILERPLATE (CoglGstVideoSink,
- cogl_gst_video_sink,
- GstBaseSink,
- GST_TYPE_BASE_SINK
- );
-
static void
cogl_gst_source_finalize (GSource *source)
{
@@ -161,27 +154,6 @@ cogl_gst_source_finalize (GSource *source)
g_mutex_clear (&gst_source->buffer_lock);
}
-static void
-cogl_gst_source_push (CoglGstSource *gst_source,
- GstBuffer *buffer)
-{
- CoglGstVideoSinkPrivate *priv = gst_source->sink->priv;
- g_mutex_lock (&gst_source->buffer_lock);
- if (gst_source->buffer)
- gst_buffer_unref (gst_source->buffer);
- gst_source->buffer = gst_buffer_ref (buffer);
- g_mutex_unlock (&gst_source->buffer_lock);
-
- g_main_context_wakeup (priv->g_ctx);
-}
-
-void
-cogl_gst_set_shader_hook (CoglGstVideoSink *sink, CoglSnippetHook hook)
-{
- sink->priv->hook = hook;
-}
-
-
CoglPipeline*
cogl_gst_video_sink_get_pipeline (CoglGstVideoSink *vt)
{
@@ -219,72 +191,12 @@ cogl_gst_source_check (GSource *source)
return gst_source->buffer != NULL;
}
-static CoglBool
-cogl_gst_source_dispatch (GSource *source,
- GSourceFunc callback,
- void* user_data)
-{
- CoglGstSource *gst_source= (CoglGstSource*) source;
- CoglGstVideoSinkPrivate *priv = gst_source->sink->priv;
- GstBuffer *buffer;
-
- if (G_UNLIKELY (priv->renderer_state == COGL_GST_RENDERER_NEED_GC))
- {
- priv->renderer->deinit (gst_source->sink);
- priv->renderer_state = COGL_GST_RENDERER_STOPPED;
- }
- if (G_UNLIKELY (priv->renderer_state == COGL_GST_RENDERER_STOPPED))
- {
- priv->renderer->init (gst_source->sink);
- priv->renderer_state = COGL_GST_RENDERER_RUNNING;
- }
-
- g_mutex_lock (&gst_source->buffer_lock);
- buffer = gst_source->buffer;
- gst_source->buffer = NULL;
- g_mutex_unlock (&gst_source->buffer_lock);
-
- if (buffer)
- {
- priv->renderer->upload (gst_source->sink, buffer);
- gst_buffer_unref (buffer);
- }
-
- return TRUE;
-}
-
-static GSourceFuncs gst_source_funcs =
-{
- cogl_gst_source_prepare,
- cogl_gst_source_check,
- cogl_gst_source_dispatch,
- cogl_gst_source_finalize
-};
-
-static CoglGstSource*
-cogl_gst_source_new (CoglGstVideoSink *sink)
-{
- GSource *source;
- CoglGstSource *gst_source;
-
- source = g_source_new (&gst_source_funcs, sizeof (CoglGstSource));
- gst_source = (CoglGstSource*) source;
-
- g_source_set_can_recurse (source, TRUE);
- g_source_set_priority (source, COGL_GST_DEFAULT_PRIORITY);
-
- gst_source->sink = sink;
- g_mutex_init (&gst_source->buffer_lock);
- gst_source->buffer = NULL;
-
- return gst_source;
-}
-
static void
cogl_gst_video_sink_set_priority (CoglGstVideoSink *sink,
int priority)
{
- g_source_set_priority ((GSource*) sink->priv->source, priority);
+ if (sink->priv->source)
+ g_source_set_priority ((GSource*) sink->priv->source, priority);
}
static void
@@ -296,13 +208,8 @@ create_template_pipeline (CoglGstVideoSink *sink,
priv->free_layer = n_layers;
if (priv->pipeline)
- {
- CoglPipeline *pln = cogl_pipeline_copy (priv->pipeline);
- cogl_object_unref (priv->pipeline);
- priv->pipeline = pln;
- }
- else
- priv->pipeline = cogl_pipeline_new (priv->ctx);
+ cogl_object_unref (priv->pipeline);
+ priv->pipeline = cogl_pipeline_new (priv->ctx);
if (decl)
{
@@ -336,7 +243,7 @@ create_template_pipeline (CoglGstVideoSink *sink,
cogl_object_unref (snippet);
}
- g_signal_emit_by_name (sink, "cogl-pipeline-ready", 0);
+ g_signal_emit_by_name (sink, "cogl-pipeline-ready", NULL);
}
static void
@@ -386,25 +293,39 @@ cogl_gst_rgb_init (CoglGstVideoSink *sink)
create_template_pipeline (sink, NULL, 1);
}
-static void
+static CoglBool
cogl_gst_rgb24_upload (CoglGstVideoSink *sink,
GstBuffer *buffer)
{
CoglGstVideoSinkPrivate *priv = sink->priv;
CoglPixelFormat format;
CoglTexture *tex;
+ GstVideoFrame frame;
if (priv->bgr)
format = COGL_PIXEL_FORMAT_BGR_888;
else
format = COGL_PIXEL_FORMAT_RGB_888;
-
- tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
- COGL_GST_TEXTURE_FLAGS, format, format,
- GST_ROUND_UP_4 (3 * priv->width),
- GST_BUFFER_DATA (buffer), NULL);
+
+ if (!gst_video_frame_map (&frame, &priv->info, buffer, GST_MAP_READ))
+ goto map_fail;
+
+ tex = cogl_texture_new_from_data (priv->ctx, priv->info.width,
+ priv->info.height, COGL_GST_TEXTURE_FLAGS,
+ format, format, priv->info.stride[0],
+ frame.data[0], NULL);
+
+ gst_video_frame_unmap (&frame);
create_paint_pipeline (sink, tex, NULL, NULL);
+
+ return TRUE;
+
+map_fail:
+ {
+ GST_ERROR_OBJECT (sink, "Could not map incoming video frame");
+ return FALSE;
+ }
}
@@ -412,75 +333,103 @@ static CoglGstRenderer rgb24_renderer =
{
"RGB 24",
COGL_GST_RGB24,
- 0,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR),
+ COGL_GST_RENDERER_NEEDS_GLSL,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGB, BGR }")),
cogl_gst_rgb_init,
cogl_gst_dummy_deinit,
cogl_gst_rgb24_upload,
};
-static void
+static CoglBool
cogl_gst_rgb32_upload (CoglGstVideoSink *sink,
GstBuffer *buffer)
{
CoglGstVideoSinkPrivate *priv = sink->priv;
CoglPixelFormat format;
CoglTexture *tex;
+ GstVideoFrame frame;
if (priv->bgr)
format = COGL_PIXEL_FORMAT_BGRA_8888;
else
format = COGL_PIXEL_FORMAT_RGBA_8888;
+
+ if (!gst_video_frame_map (&frame, &priv->info, buffer, GST_MAP_READ))
+ goto map_fail;
- tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
- COGL_GST_TEXTURE_FLAGS, format, format,
- GST_ROUND_UP_4 (4 * priv->width),
- GST_BUFFER_DATA (buffer), NULL);
+ tex = cogl_texture_new_from_data (priv->ctx, priv->info.width,
+ priv->info.height, COGL_GST_TEXTURE_FLAGS,
+ format, format, priv->info.stride[0],
+ frame.data[0], NULL);
+
+ gst_video_frame_unmap (&frame);
create_paint_pipeline (sink, tex, NULL, NULL);
+
+ return TRUE;
+
+map_fail:
+ {
+ GST_ERROR_OBJECT (sink, "Could not map incoming video frame");
+ return FALSE;
+ }
}
static CoglGstRenderer rgb32_renderer =
{
"RGB 32",
COGL_GST_RGB32,
- 0,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA),
+ COGL_GST_RENDERER_NEEDS_GLSL,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, BGRA }")),
cogl_gst_rgb_init,
cogl_gst_dummy_deinit,
cogl_gst_rgb32_upload,
};
-static void
+static CoglBool
cogl_gst_yv12_upload (CoglGstVideoSink *sink,
GstBuffer *buffer)
{
CoglGstVideoSinkPrivate *priv = sink->priv;
- int y_row_stride = GST_ROUND_UP_4 (priv->width);
- int uv_row_stride = GST_ROUND_UP_4 (priv->width / 2);
CoglTexture *y_tex, *u_tex, *v_tex;
-
+ GstVideoFrame frame;
CoglPixelFormat format = COGL_PIXEL_FORMAT_G_8;
-
- y_tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
- COGL_GST_TEXTURE_FLAGS, format, format,
- y_row_stride, GST_BUFFER_DATA (buffer),
- NULL);
-
- u_tex = cogl_texture_new_from_data (priv->ctx, priv->width / 2,
- priv->height / 2, COGL_GST_TEXTURE_FLAGS,
- format, format, uv_row_stride,
- GST_BUFFER_DATA (buffer) +
- (y_row_stride * priv->height), NULL);
-
- v_tex = cogl_texture_new_from_data (priv->ctx, priv->width / 2,
- priv->height / 2, COGL_GST_TEXTURE_FLAGS,
- format, format, uv_row_stride,
- GST_BUFFER_DATA (buffer) +
- (y_row_stride * priv->height) +
- (uv_row_stride * priv->height / 2), NULL);
+
+ if (!gst_video_frame_map (&frame, &priv->info, buffer, GST_MAP_READ))
+ goto map_fail;
+
+ y_tex =
+ cogl_texture_new_from_data (priv->ctx,
+ GST_VIDEO_INFO_COMP_WIDTH (&priv->info, 0),
+ GST_VIDEO_INFO_COMP_HEIGHT (&priv->info, 0),
+ COGL_GST_TEXTURE_FLAGS, format, format,
+ priv->info.stride[0], frame.data[0], NULL);
+
+ u_tex =
+ cogl_texture_new_from_data (priv->ctx,
+ GST_VIDEO_INFO_COMP_WIDTH (&priv->info, 1),
+ GST_VIDEO_INFO_COMP_HEIGHT (&priv->info, 1),
+ COGL_GST_TEXTURE_FLAGS, format, format,
+ priv->info.stride[1], frame.data[1], NULL);
+
+ v_tex =
+ cogl_texture_new_from_data (priv->ctx,
+ GST_VIDEO_INFO_COMP_WIDTH (&priv->info, 2),
+ GST_VIDEO_INFO_COMP_HEIGHT (&priv->info, 2),
+ COGL_GST_TEXTURE_FLAGS, format, format,
+ priv->info.stride[2], frame.data[2], NULL);
+
+ gst_video_frame_unmap (&frame);
create_paint_pipeline (sink, y_tex, u_tex, v_tex);
+
+ return TRUE;
+
+map_fail:
+ {
+ GST_ERROR_OBJECT (sink, "Could not map incoming video frame");
+ return FALSE;
+ }
}
static void
@@ -496,7 +445,7 @@ static CoglGstRenderer yv12_glsl_renderer =
"YV12 glsl",
COGL_GST_YV12,
COGL_GST_RENDERER_NEEDS_GLSL,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YV12")),
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("YV12")),
cogl_gst_yv12_glsl_init,
cogl_gst_dummy_deinit,
cogl_gst_yv12_upload,
@@ -515,7 +464,7 @@ static CoglGstRenderer i420_glsl_renderer =
"I420 glsl",
COGL_GST_I420,
COGL_GST_RENDERER_NEEDS_GLSL,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")),
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")),
cogl_gst_i420_glsl_init,
cogl_gst_dummy_deinit,
cogl_gst_yv12_upload,
@@ -529,20 +478,34 @@ cogl_gst_ayuv_glsl_init (CoglGstVideoSink *sink)
1);
}
-static void
+static CoglBool
cogl_gst_ayuv_upload (CoglGstVideoSink *sink,
GstBuffer *buffer)
{
CoglGstVideoSinkPrivate *priv = sink->priv;
CoglPixelFormat format = COGL_PIXEL_FORMAT_RGBA_8888;
CoglTexture *tex;
-
- tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
- COGL_GST_TEXTURE_FLAGS, format, format,
- GST_ROUND_UP_4 (4 * priv->width),
- GST_BUFFER_DATA (buffer), NULL);
+ GstVideoFrame frame;
+
+ if (!gst_video_frame_map (&frame, &priv->info, buffer, GST_MAP_READ))
+ goto map_fail;
+
+ tex = cogl_texture_new_from_data (priv->ctx, priv->info.width,
+ priv->info.height, COGL_GST_TEXTURE_FLAGS,
+ format, format, priv->info.stride[0],
+ frame.data[0], NULL);
+
+ gst_video_frame_unmap (&frame);
create_paint_pipeline (sink, tex, NULL, NULL);
+
+ return TRUE;
+
+map_fail:
+ {
+ GST_ERROR_OBJECT (sink, "Could not map incoming video frame");
+ return FALSE;
+ }
}
static CoglGstRenderer ayuv_glsl_renderer =
@@ -550,24 +513,90 @@ static CoglGstRenderer ayuv_glsl_renderer =
"AYUV glsl",
COGL_GST_AYUV,
COGL_GST_RENDERER_NEEDS_GLSL,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")),
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("AYUV")),
cogl_gst_ayuv_glsl_init,
cogl_gst_dummy_deinit,
cogl_gst_ayuv_upload,
};
+#ifdef HAVE_HW_DECODER_SUPPORT
+
+static void
+cogl_gst_hw_init (CoglGstVideoSink *sink)
+{
+ create_template_pipeline (sink, NULL, NULL, FALSE, 1);
+}
+
+static void
+cogl_gst_hw_deinit (CoglGstVideoSink* sink)
+{
+ if (sink->priv->converter != NULL)
+ g_object_unref (sink->priv->converter);
+ sink->priv->converter = NULL;
+}
+
+static void
+cogl_gst_hw_upload (CoglGstVideoSink *sink,
+ GstBuffer *buffer)
+{
+ CoglGstVideoSinkPriv *priv = sink->priv;
+ GstSurfaceMeta* surface = gst_buffer_get_surface_meta (buffer);
+
+ g_return_if_fail (surface != NULL);
+
+ if (G_UNLIKELY (priv->converter == NULL))
+ {
+ CoglTexture* tex;
+ unsigned int gl_tex;
+ unsigned int gl_tar;
+ GValue value = {0};
+
+ tex = cogl_texture_new_with_size (priv->ctx, priv->info.width,
+ priv->info.height,
+ COGL_GST_TEXTURE_FLAGS,
+ COGL_PIXEL_FORMAT_BGRA_8888, NULL);
+
+ cogl_pipeline_set_layer_texture (priv->pipeline, 0, tex);
+ cogl_texture_get_gl_texture (tex, &gl_texture, &gl_target);
+
+ g_value_init (&value, gl_texture);
+ g_value_set_uint (&value, gl_texture);
+
+ priv->converter = gst_surface_meta_create_converter (surface, "opengl"
+ &value);
+ cogl_object_unref (tex);
+ g_return_if_fail (priv->converter);
+ }
+ gst_surface_converter_upload (priv->converter, buffer);
+}
+
+static CoglGstRenderer hw_renderer = {
+ "HW surface",
+ COGL_GST_SURFACE,
+ 0,
+ GST_STATIC_CAPS ("x-video/surface, opengl=true"),
+ cogl_gst_hw_init,
+ cogl_gst_hw_deinit,
+ cogl_gst_hw_upload,
+};
+
+#endif
+
static GSList*
cogl_gst_build_renderers_list (CoglContext *ctx)
{
GSList *list = NULL;
CoglBool has_glsl;
int i;
- static CoglGstRenderer * const renderers[] =
+ static CoglGstRenderer *const renderers[] =
{
&rgb24_renderer,
&rgb32_renderer,
&yv12_glsl_renderer,
&i420_glsl_renderer,
+ #ifdef HAVE_HW_DECODER_SUPPORT
+ &hw_renderer,
+ #endif
&ayuv_glsl_renderer
};
@@ -587,7 +616,6 @@ append_cap (gpointer data,
CoglGstRenderer *renderer = (CoglGstRenderer*) data;
GstCaps *caps = (GstCaps*) user_data;
GstCaps *writable_caps;
-
writable_caps =
gst_caps_make_writable (gst_static_caps_get (&renderer->caps));
gst_caps_append (caps, writable_caps);
@@ -654,50 +682,110 @@ cogl_gst_find_renderer_by_format (CoglGstVideoSink *sink,
return renderer;
}
-static void
-cogl_gst_video_sink_base_init (void *g_class)
+static GstCaps*
+cogl_gst_video_sink_get_caps (GstBaseSink *bsink,
+ GstCaps *filter)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sinktemplate_all));
- gst_element_class_set_details (element_class, &cogl_gst_video_sink_details);
-
+ CoglGstVideoSink *sink;
+ sink = COGL_GST_VIDEO_SINK (bsink);
+ return gst_caps_ref (sink->priv->caps);
}
-
-static void
-cogl_gst_video_sink_init (CoglGstVideoSink *sink,
- CoglGstVideoSinkClass *klass)
+static CoglBool
+cogl_gst_video_sink_parse_caps (GstCaps *caps,
+ CoglGstVideoSink *sink,
+ CoglBool save)
{
- CoglGstVideoSinkPrivate* priv;
+ CoglGstVideoSinkPrivate *priv = sink->priv;
+ GstCaps *intersection;
+ GstVideoInfo vinfo;
+ CoglGstVideoFormat format;
+ CoglBool bgr = FALSE;
+ CoglGstRenderer* renderer;
+
+ intersection = gst_caps_intersect (priv->caps, caps);
+ if (gst_caps_is_empty (intersection))
+ goto no_intersection;
+
+ gst_caps_unref (intersection);
+
+ if (!gst_video_info_from_caps (&vinfo, caps))
+ goto unknown_format;
+
+ switch (vinfo.finfo->format) {
+ case GST_VIDEO_FORMAT_YV12:
+ format = COGL_GST_YV12;
+ break;
+ case GST_VIDEO_FORMAT_I420:
+ format = COGL_GST_I420;
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ format = COGL_GST_AYUV;
+ bgr = FALSE;
+ break;
+ case GST_VIDEO_FORMAT_RGB:
+ format = COGL_GST_RGB24;
+ bgr = FALSE;
+ break;
+ case GST_VIDEO_FORMAT_BGR:
+ format = COGL_GST_RGB24;
+ bgr = TRUE;
+ break;
+ case GST_VIDEO_FORMAT_RGBA:
+ format = COGL_GST_RGB32;
+ bgr = FALSE;
+ break;
+ case GST_VIDEO_FORMAT_BGRA:
+ format = COGL_GST_RGB32;
+ bgr = TRUE;
+ break;
+ default:
+ goto unhandled_format;
+ }
+
+ renderer = cogl_gst_find_renderer_by_format (sink, format);
- sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
- COGL_GST_TYPE_VIDEO_SINK,
- CoglGstVideoSinkPrivate);
+ if (G_UNLIKELY (renderer == NULL))
+ goto no_suitable_renderer;
- sink->priv->loop = g_main_loop_new (NULL, TRUE);
- sink->priv->g_ctx = g_main_loop_get_context (sink->priv->loop);
+ GST_INFO_OBJECT (sink, "found the %s renderer", renderer->name);
- priv->renderer_state = COGL_GST_RENDERER_STOPPED;
- priv->hook = COGL_SNIPPET_HOOK_FRAGMENT;
-}
+ if (save) {
+ priv->info = vinfo;
-static GstFlowReturn
-_cogl_gst_video_sink_render (GstBaseSink *bsink,
- GstBuffer *buffer)
-{
- CoglGstVideoSink *sink = COGL_GST_VIDEO_SINK (bsink);
- cogl_gst_source_push (sink->priv->source, buffer);
+ priv->format = format;
+ priv->bgr = bgr;
- return GST_FLOW_OK;
-}
+ priv->renderer = renderer;
+ }
-static GstCaps*
-cogl_gst_video_sink_get_caps (GstBaseSink *bsink)
-{
- CoglGstVideoSink *sink;
- sink = COGL_GST_VIDEO_SINK (bsink);
- return gst_caps_ref (sink->priv->caps);
+ return TRUE;
+
+
+no_intersection:
+ {
+ GST_WARNING_OBJECT (sink,
+ "Incompatible caps, don't intersect with %" GST_PTR_FORMAT, priv->caps);
+ return FALSE;
+ }
+
+unknown_format:
+ {
+ GST_WARNING_OBJECT (sink, "Could not figure format of input caps");
+ return FALSE;
+ }
+
+unhandled_format:
+ {
+ GST_ERROR_OBJECT (sink, "Provided caps aren't supported by clutter-gst");
+ return FALSE;
+ }
+
+no_suitable_renderer:
+ {
+ GST_ERROR_OBJECT (sink, "could not find a suitable renderer");
+ return FALSE;
+ }
}
static CoglBool
@@ -706,88 +794,153 @@ cogl_gst_video_sink_set_caps (GstBaseSink *bsink,
{
CoglGstVideoSink *sink;
CoglGstVideoSinkPrivate *priv;
- GstCaps *intersection;
- GstStructure *structure;
- CoglBool ret;
- const GValue *fps;
- const GValue *par;
- int width, height;
- uint32_t fourcc;
- int red_mask, blue_mask;
sink = COGL_GST_VIDEO_SINK (bsink);
priv = sink->priv;
- intersection = gst_caps_intersect (priv->caps, caps);
- if (gst_caps_is_empty (intersection))
+ if (!cogl_gst_video_sink_parse_caps (caps, sink, FALSE))
return FALSE;
- gst_caps_unref (intersection);
+ g_mutex_lock (&priv->source->buffer_lock);
+ priv->source->has_new_caps = TRUE;
+ g_mutex_unlock (&priv->source->buffer_lock);
- structure = gst_caps_get_structure (caps, 0);
+ return TRUE;
+}
- ret = gst_structure_get_int (structure, "width", &width);
- ret &= gst_structure_get_int (structure, "height", &height);
- fps = gst_structure_get_value (structure, "framerate");
- ret &= (fps != NULL);
+static CoglBool
+cogl_gst_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ void* user_data)
+{
+ CoglGstSource *gst_source= (CoglGstSource*) source;
+ CoglGstVideoSinkPrivate *priv = gst_source->sink->priv;
+ GstBuffer *buffer;
- par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+ g_mutex_lock (&gst_source->buffer_lock);
+
+ if (G_UNLIKELY (gst_source->has_new_caps))
+ {
+ GstCaps *caps =
+ gst_pad_get_current_caps (GST_BASE_SINK_PAD ((GST_BASE_SINK
+ (gst_source->sink))));
- if (!ret)
- return FALSE;
+ if (priv->renderer)
+ priv->renderer->deinit (gst_source->sink);
+
+ if (!cogl_gst_video_sink_parse_caps (caps, gst_source->sink, TRUE))
+ goto negotiation_fail;
- priv->width = width;
- priv->height = height;
+ priv->renderer->init (gst_source->sink);
+ gst_source->has_new_caps = FALSE;
+ }
+
+ buffer = gst_source->buffer;
+ gst_source->buffer = NULL;
- priv->fps_n = gst_value_get_fraction_numerator (fps);
- priv->fps_d = gst_value_get_fraction_denominator (fps);
+ g_mutex_unlock (&gst_source->buffer_lock);
- if (par)
- {
- priv->par_n = gst_value_get_fraction_numerator (par);
- priv->par_d = gst_value_get_fraction_denominator (par);
- }
- else
- priv->par_n = priv->par_d = 1;
-
- ret = gst_structure_get_fourcc (structure, "format", &fourcc);
- if (ret && (fourcc == GST_MAKE_FOURCC ('Y', 'V', '1', '2')))
- priv->format = COGL_GST_YV12;
- else if (ret && (fourcc == GST_MAKE_FOURCC ('I', '4', '2', '0')))
- priv->format = COGL_GST_I420;
- else if (ret && (fourcc == GST_MAKE_FOURCC ('A', 'Y', 'U', 'V')))
+ if (buffer)
{
- priv->format = COGL_GST_AYUV;
- priv->bgr = FALSE;
- }
+ if (!priv->renderer->upload (gst_source->sink, buffer))
+ goto fail_upload;
+
+ g_signal_emit_by_name (gst_source->sink, "cogl-gst-new-frame", NULL);
+ gst_buffer_unref (buffer);
+ }
else
- {
- uint32_t mask;
- gst_structure_get_int (structure, "red_mask", &red_mask);
- gst_structure_get_int (structure, "blue_mask", &blue_mask);
+ GST_WARNING_OBJECT (gst_source->sink, "No buffers available for display");
- mask = red_mask | blue_mask;
+ return TRUE;
- if (mask < 0x1000000)
- {
- priv->format = COGL_GST_RGB24;
- priv->bgr = (red_mask == 0xff0000) ? FALSE : TRUE;
- }
- else
- {
- priv->format = COGL_GST_RGB32;
- priv->bgr = (red_mask == 0xff000000) ? FALSE : TRUE;
- }
- }
- priv->renderer = cogl_gst_find_renderer_by_format (sink, priv->format);
- if (priv->renderer == NULL)
- {
- GST_ERROR_OBJECT (sink, "Could not find suitable renderer");
- return FALSE;
- }
+negotiation_fail:
+ {
+ GST_WARNING_OBJECT (gst_source->sink,
+ "Failed to handle caps. Stopping GSource");
+ priv->flow_return = GST_FLOW_NOT_NEGOTIATED;
+ g_mutex_unlock (&gst_source->buffer_lock);
- return TRUE;
+ return FALSE;
+ }
+
+fail_upload:
+ {
+ GST_WARNING_OBJECT (gst_source->sink, "Failed to upload buffer");
+ priv->flow_return = GST_FLOW_ERROR;
+ gst_buffer_unref (buffer);
+ return FALSE;
+ }
+}
+
+static GSourceFuncs gst_source_funcs =
+{
+ cogl_gst_source_prepare,
+ cogl_gst_source_check,
+ cogl_gst_source_dispatch,
+ cogl_gst_source_finalize
+};
+
+static CoglGstSource*
+cogl_gst_source_new (CoglGstVideoSink *sink)
+{
+ GSource *source;
+ CoglGstSource *gst_source;
+
+ source = g_source_new (&gst_source_funcs, sizeof (CoglGstSource));
+ gst_source = (CoglGstSource*) source;
+
+ g_source_set_can_recurse (source, TRUE);
+ g_source_set_priority (source, COGL_GST_DEFAULT_PRIORITY);
+
+ gst_source->sink = sink;
+ g_mutex_init (&gst_source->buffer_lock);
+ gst_source->buffer = NULL;
+
+ return gst_source;
+}
+
+static void
+cogl_gst_video_sink_init (CoglGstVideoSink *sink)
+{
+ CoglGstVideoSinkPrivate* priv;
+
+ sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
+ COGL_GST_TYPE_VIDEO_SINK,
+ CoglGstVideoSinkPrivate);
+
+ sink->priv->loop = g_main_loop_new (NULL, TRUE);
+ sink->priv->g_ctx = g_main_loop_get_context (sink->priv->loop);
+}
+
+static GstFlowReturn
+_cogl_gst_video_sink_render (GstBaseSink *bsink,
+ GstBuffer *buffer)
+{
+ CoglGstVideoSink *sink = COGL_GST_VIDEO_SINK (bsink);
+ CoglGstVideoSinkPrivate *priv = sink->priv;
+ CoglGstSource *gst_source = priv->source;
+
+ g_mutex_lock (&gst_source->buffer_lock);
+
+ if (G_UNLIKELY (priv->flow_return != GST_FLOW_OK))
+ goto dispatch_flow_ret;
+
+ if (gst_source->buffer)
+ gst_buffer_unref (gst_source->buffer);
+
+ gst_source->buffer = gst_buffer_ref (buffer);
+ g_mutex_unlock (&gst_source->buffer_lock);
+
+ g_main_context_wakeup (priv->g_ctx);
+
+ return GST_FLOW_OK;
+
+ dispatch_flow_ret:
+ {
+ g_mutex_unlock (&gst_source->buffer_lock);
+ return priv->flow_return;
+ }
}
static void
@@ -798,12 +951,11 @@ cogl_gst_video_sink_dispose (GObject *object)
self = COGL_GST_VIDEO_SINK (object);
priv = self->priv;
-
- if (priv->renderer_state == COGL_GST_RENDERER_RUNNING ||
- priv->renderer_state == COGL_GST_RENDERER_NEED_GC)
+
+ if (priv->renderer)
{
priv->renderer->deinit (self);
- priv->renderer_state = COGL_GST_RENDERER_STOPPED;
+ priv->renderer = NULL;
}
if (priv->pipeline)
@@ -818,7 +970,7 @@ cogl_gst_video_sink_dispose (GObject *object)
priv->caps = NULL;
}
- G_OBJECT_CLASS (parent_class)->dispose (object);
+ G_OBJECT_CLASS(parent_class)->dispose (object);
}
static void
@@ -839,6 +991,7 @@ cogl_gst_video_sink_start (GstBaseSink *base_sink)
priv->source = cogl_gst_source_new (sink);
g_source_attach ((GSource*) priv->source, priv->g_ctx);
+ priv->flow_return = GST_FLOW_OK;
return TRUE;
}
@@ -895,8 +1048,6 @@ cogl_gst_video_sink_stop (GstBaseSink *base_sink)
priv->source = NULL;
}
- priv->renderer_state = COGL_GST_RENDERER_STOPPED;
-
return TRUE;
}
@@ -905,13 +1056,24 @@ cogl_gst_video_sink_class_init (CoglGstVideoSinkClass *klass)
{
GObjectClass *go_class = G_OBJECT_CLASS (klass);
GstBaseSinkClass *gb_class = GST_BASE_SINK_CLASS (klass);
- GParamSpec *pspec;
+ GstElementClass *ge_class = GST_ELEMENT_CLASS (klass);
+ GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (CoglGstVideoSinkPrivate));
go_class->set_property = cogl_gst_video_sink_set_property;
go_class->get_property = cogl_gst_video_sink_get_property;
go_class->dispose = cogl_gst_video_sink_dispose;
go_class->finalize = cogl_gst_video_sink_finalize;
+
+ gst_element_class_add_pad_template (ge_class,
+ gst_static_pad_template_get (&sinktemplate_all));
+ gst_element_class_set_metadata (ge_class, "Cogl video sink", "Sink/Video",
+ "Sends video data from GStreamer to a Cogl pipeline",
+ "Jonathan Matthew <jonathan kaolin wh9 net>, "
+ "Matthew Allum <mallum o-hand com, "
+ "Chris Lord <chris o-hand com>, "
+ "Plamena Manolova <plamena n manolova intel com>");
+
gb_class->render = _cogl_gst_video_sink_render;
gb_class->preroll = _cogl_gst_video_sink_render;
gb_class->start = cogl_gst_video_sink_start;
@@ -931,18 +1093,40 @@ cogl_gst_video_sink_class_init (CoglGstVideoSinkClass *klass)
g_signal_new ("cogl-pipeline-ready", COGL_GST_TYPE_VIDEO_SINK,
G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, G_TYPE_NONE);
+
+ g_signal_new ("cogl-gst-new-frame", COGL_GST_TYPE_VIDEO_SINK,
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0, G_TYPE_NONE);
+}
+CoglGstVideoSink*
+cogl_gst_video_sink_new (CoglContext *ctx)
+{
+ CoglGstVideoSink* sink = g_object_new (COGL_GST_TYPE_VIDEO_SINK, NULL);
+ cogl_gst_video_sink_set_context (sink, ctx);
+
+ return sink;
}
+
static CoglBool
-plugin_init (GstPlugin *plugin)
+_plugin_init (GstPlugin * coglgstvideosink)
{
- CoglBool ret = gst_element_register (plugin, "coglsink", GST_RANK_PRIMARY,
- COGL_GST_TYPE_VIDEO_SINK);
-
- return ret;
+ return gst_element_register (coglgstvideosink, "coglsink", GST_RANK_PRIMARY,
+ COGL_GST_TYPE_VIDEO_SINK);
}
-GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR, GST_VERSION_MINOR, "coglsink",
- "Element to attach frames to cogl pipelines",
- plugin_init, VERSION, "LGPL", PACKAGE, "...");
+GST_PLUGIN_DEFINE (
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ cogl,
+ "Sends video data from GStreamer to a Cogl pipeline",
+ _plugin_init,
+ VERSION,
+ "LGPL",
+ "CoglGst",
+ "http://gstreamer.net/"
+)
+
+
+
diff --git a/cogl-gst/cogl-gst-video-sink.h b/cogl-gst/cogl-gst-video-sink.h
index d3d9580..decf284 100644
--- a/cogl-gst/cogl-gst-video-sink.h
+++ b/cogl-gst/cogl-gst-video-sink.h
@@ -29,6 +29,7 @@
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
+ FLOP
*/
#ifndef __COGL_GST_VIDEO_SINK_H__
@@ -90,6 +91,9 @@ struct _CoglGstVideoSinkClass
GType cogl_gst_video_sink_get_type (void) G_GNUC_CONST;
+CoglGstVideoSink*
+cogl_gst_video_sink_new (CoglContext *ctx);
+
CoglPipeline*
cogl_gst_video_sink_get_pipeline (CoglGstVideoSink *vt);
diff --git a/configure.ac b/configure.ac
index 2404545..28dc240 100644
--- a/configure.ac
+++ b/configure.ac
@@ -447,10 +447,20 @@ AC_ARG_ENABLE(
)
AS_IF([test "x$enable_cogl_gst" = "xyes"],
[
- COGL_GST_PKG_REQUIRES="$COGL_GST_PKG_REQUIRES gstreamer-0.10 >= 0.10 gstreamer-fft-0.10 >= 0.10
gstreamer-interfaces-0.10 >= 0.10 gstreamer-base-0.10 >= 0.10"
+ COGL_GST_PKG_REQUIRES="$COGL_GST_PKG_REQUIRES gstreamer-1.0 gstreamer-fft-1.0 \
+ gstreamer-audio-1.0 gstreamer-base-1.0 \
+ gstreamer-video-1.0 gstreamer-plugins-base-1.0 \
+ gstreamer-tag-1.0 gstreamer-controller-1.0"
+
+ GST_MAJORMINOR=1.0
+
+ dnl define location of gstreamer plugin directory
+ plugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR"
+ AC_SUBST(plugindir)
]
)
+
dnl ============================================================
dnl Choose image loading backend
dnl ============================================================
diff --git a/examples/cogl-basic-video-player.c b/examples/cogl-basic-video-player.c
index 2f72a74..183b1e3 100644
--- a/examples/cogl-basic-video-player.c
+++ b/examples/cogl-basic-video-player.c
@@ -58,20 +58,13 @@ _frame_callback (CoglOnscreen *onscreen,
}
static CoglBool
-_draw (void *user_data)
+_draw (gpointer instance,
+ gpointer user_data)
{
Data *data = (Data*) user_data;
CoglPipeline* current = cogl_gst_video_sink_get_pipeline (data->sink);
-/*
- * This checks whether the system compositor is ready to render and that
- * sink has retrieved a new frame (the cogl sink creates a new cogl pipeline
- * (by copying the previous one) for each frame so checking whether the
- * pipeline has changed is a way of querying whether there is a new frame to
- * render).
- */
-
- if (data->draw_ready && current != data->pln && current)
+ if (data->draw_ready)
{
cogl_framebuffer_clear4f (data->fb,
COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_DEPTH, 0,
@@ -108,7 +101,7 @@ _set_up_pipeline (gpointer instance,
cogl_onscreen_add_frame_callback(COGL_ONSCREEN (data->fb), _frame_callback,
&data, NULL);
- g_idle_add (_draw, data);
+ g_signal_connect (data->sink,"cogl-gst-new-frame", G_CALLBACK (_draw), data);
}
int
@@ -119,9 +112,12 @@ main (int argc,
CoglContext *ctx;
CoglOnscreen *onscreen;
CoglMatrix view;
- CoglGstVideoPlayer *player;
GMainLoop *loop;
float fovy, aspect, z_near, z_2d, z_far;
+ GstElement *pipeline;
+ GstElement *bin;
+ GstBus *bus;
+ char *uri;
ctx = cogl_context_new (NULL, NULL);
onscreen = cogl_onscreen_new (ctx, 640, 480);
@@ -142,13 +138,28 @@ main (int argc,
cogl_framebuffer_set_modelview_matrix (data.fb, &view);
gst_init (&argc, &argv);
+
+ data.sink = cogl_gst_video_sink_new (ctx);
+
+ pipeline = gst_pipeline_new ("gst-player");
+ bin = gst_element_factory_make ("playbin", "bin");
+
+ if (argc < 2)
+ uri = "http://docs.gstreamer.com/media/sintel_trailer-480p.webm";
+ else
+ uri = argv[1];
+
+ g_object_set (G_OBJECT (bin), "video-sink", GST_ELEMENT (data.sink), NULL);
+
- player = cogl_gst_video_player_new (ctx, TRUE,
- "http://docs.gstreamer.com/media/sintel_trailer-480p.webm");
+ gst_bin_add (GST_BIN (pipeline), bin);
- data.sink = cogl_gst_video_player_get_sink (player);
+ g_object_set (G_OBJECT (bin), "uri", uri, NULL);
+
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+ gst_bus_add_watch (bus, _bus_watch, &data);
- cogl_gst_video_player_add_bus_watch (player, _bus_watch, &data);
loop = cogl_gst_video_sink_get_main_loop (data.sink);
g_signal_connect (data.sink, "cogl-pipeline-ready",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]