[062/906] git-svn-id: svn://svn.wobow.com/GStreamer_playground/gst-plugins-gl@421 93df14bb-0f41-7a43-8087-d3e2a2f0e464

This commit is contained in:
Julien Isorce 2008-05-18 11:12:46 +00:00 committed by Matthew Waters
parent f1744c26ec
commit a5ff5ff14e
11 changed files with 3707 additions and 0 deletions

View file

@ -0,0 +1,124 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglbuffer.h"
static GObjectClass* gst_gl_buffer_parent_class;
static void
gst_gl_buffer_finalize (GstGLBuffer* buffer)
{
//wait clear textures end, blocking call
gst_gl_display_clearTexture (buffer->display, buffer->texture,
buffer->texture_u, buffer->texture_v);
g_object_unref (buffer->display);
GST_MINI_OBJECT_CLASS (gst_gl_buffer_parent_class)->
finalize (GST_MINI_OBJECT (buffer));
}
static void
gst_gl_buffer_init (GstGLBuffer* buffer, gpointer g_class)
{
buffer->display = NULL;
buffer->video_format = 0;
buffer->texture = 0;
buffer->texture_u = 0;
buffer->texture_v = 0;
buffer->width = 0;
buffer->height = 0;
}
static void
gst_gl_buffer_class_init (gpointer g_class, gpointer class_data)
{
GstMiniObjectClass* mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
gst_gl_buffer_parent_class = g_type_class_peek_parent (g_class);
mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
gst_gl_buffer_finalize;
}
GType
gst_gl_buffer_get_type (void)
{
static GType _gst_gl_buffer_type;
if (G_UNLIKELY (_gst_gl_buffer_type == 0)) {
static const GTypeInfo info = {
sizeof (GstBufferClass),
NULL,
NULL,
gst_gl_buffer_class_init,
NULL,
NULL,
sizeof (GstGLBuffer),
0,
(GInstanceInitFunc) gst_gl_buffer_init,
NULL
};
_gst_gl_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
"GstGLBuffer", &info, 0);
}
return _gst_gl_buffer_type;
}
GstGLBuffer*
gst_gl_buffer_new_from_video_format (GstGLDisplay* display,
GstVideoFormat video_format, gint context_width, gint context_height,
gint width, gint height)
{
GstGLBuffer *buffer;
g_return_val_if_fail (video_format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
g_return_val_if_fail (display != NULL, NULL);
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
buffer = (GstGLBuffer *) gst_mini_object_new (GST_TYPE_GL_BUFFER);
buffer->display = g_object_ref (display);
buffer->width = width;
buffer->height = height;
buffer->video_format = video_format;
GST_BUFFER_SIZE (buffer) = gst_gl_buffer_format_get_size (video_format, context_width, context_height);
//blocking call, init texture
gst_gl_display_textureRequested (buffer->display, buffer->video_format,
buffer->width, buffer->height,
&buffer->texture, &buffer->texture_u, &buffer->texture_v) ;
return buffer;
}
int
gst_gl_buffer_format_get_size (GstVideoFormat format, int width, int height)
{
/* this is not strictly true, but it's used for compatibility with
* queue and BaseTransform */
return width * height * 4;
}
gboolean
gst_gl_buffer_format_parse_caps (GstCaps * caps, GstVideoFormat * format,
gint* width, gint* height)
{
GstStructure *structure;
gboolean ret;
structure = gst_caps_get_structure (caps, 0);
if (!gst_structure_has_name (structure, "video/x-raw-gl"))
return FALSE;
ret = gst_structure_get_int (structure, "width", width);
ret &= gst_structure_get_int (structure, "height", height);
return ret;
}

View file

@ -0,0 +1,54 @@
#ifndef _GST_GL_BUFFER_H_
#define _GST_GL_BUFFER_H_
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstgldisplay.h"
typedef struct _GstGLBuffer GstGLBuffer;
#define GST_TYPE_GL_BUFFER (gst_gl_buffer_get_type())
#define GST_IS_GL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_BUFFER))
#define GST_GL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_BUFFER, GstGLBuffer))
struct _GstGLBuffer {
GstBuffer buffer;
GstGLDisplay *display;
GstVideoFormat video_format;
GLuint texture;
GLuint texture_u;
GLuint texture_v;
gint width;
gint height;
};
GType gst_gl_buffer_get_type (void);
#define gst_gl_buffer_ref(x) ((GstGLBuffer *)(gst_buffer_ref((GstBuffer *)(x))))
#define gst_gl_buffer_unref(x) (gst_buffer_unref((GstBuffer *)(x)))
GstGLBuffer* gst_gl_buffer_new_from_video_format (GstGLDisplay* display, GstVideoFormat format,
gint context_width, gint context_height,
gint width, gint height);
gint gst_gl_buffer_format_get_size (GstVideoFormat format, gint width, gint height);
gboolean gst_gl_buffer_format_parse_caps (GstCaps* caps, GstVideoFormat* format,
gint* width, gint* height);
#define GST_GL_VIDEO_CAPS \
"video/x-raw-gl," \
"width=(int)[1,1920]," \
"height=(int)[1,1080]," \
"pixel-aspect-ratio=(fraction)1/1," \
"framerate=(fraction)[0/1,100/1]"
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,195 @@
#ifndef __GST_GL_H__
#define __GST_GL_H__
#include <gl/glew.h>
#include <GL/freeglut.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#define GST_TYPE_GL_DISPLAY \
(gst_gl_display_get_type())
#define GST_GL_DISPLAY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DISPLAY,GstGLDisplay))
#define GST_GL_DISPLAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_DISPLAY,GstGLDisplayClass))
#define GST_IS_GL_DISPLAY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DISPLAY))
#define GST_IS_GL_DISPLAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_DISPLAY))
typedef struct _GstGLDisplay GstGLDisplay;
typedef struct _GstGLDisplayClass GstGLDisplayClass;
//Message type
typedef enum {
GST_GL_DISPLAY_ACTION_CREATE,
GST_GL_DISPLAY_ACTION_DESTROY,
GST_GL_DISPLAY_ACTION_VISIBLE,
GST_GL_DISPLAY_ACTION_PREPARE,
GST_GL_DISPLAY_ACTION_CHANGE,
GST_GL_DISPLAY_ACTION_CLEAR,
GST_GL_DISPLAY_ACTION_VIDEO,
GST_GL_DISPLAY_ACTION_REDISPLAY
} GstGLDisplayAction;
//Message to communicate with the glut thread
typedef struct _GstGLDisplayMsg {
GstGLDisplayAction action;
gint glutWinId;
GstGLDisplay* display;
} GstGLDisplayMsg;
//Texture pool elements
typedef struct _GstGLDisplayTex {
GLuint texture;
GLuint texture_u;
GLuint texture_v;
} GstGLDisplayTex;
//Client callbacks
typedef void (* CRCB) ( GLuint, GLuint );
typedef gboolean (* CDCB) ( GLuint, GLuint, GLuint);
struct _GstGLDisplay {
GObject object;
GMutex *mutex;
GQueue* texturePool;
GCond *cond_make;
GCond *cond_fill;
GCond *cond_clear;
GCond *cond_video;
GCond *cond_create;
GCond *cond_destroy;
gint glutWinId;
gulong winId;
GString *title;
gint win_xpos;
gint win_ypos;
gint glcontext_width;
gint glcontext_height;
gboolean visible;
//intput frame buffer object (video -> GL)
GLuint fbo;
GLuint depthBuffer;
GLuint textureFBO;
GLuint textureFBOWidth;
GLuint textureFBOHeight;
//graphic frame buffer object (GL texture -> GL scene)
GLuint graphicFBO;
GLuint graphicDepthBuffer;
GLuint graphicTexture;
GLuint requestedTexture;
GLuint requestedTexture_u;
GLuint requestedTexture_v;
GstVideoFormat requestedVideo_format;
GLuint requestedTextureWidth;
GLuint requestedTextureHeight;
GLuint candidateTexture;
GLuint candidateTexture_u;
GLuint candidateTexture_v;
GstVideoFormat candidateVideo_format;
GLuint candidateTextureWidth;
GLuint candidateTextureHeight;
gpointer candidateData;
GLuint currentTexture;
GLuint currentTexture_u;
GLuint currentTexture_v;
GstVideoFormat currentVideo_format;
GLuint currentTextureWidth;
GLuint currentTextureHeight;
GLuint textureTrash;
GLuint textureTrash_u;
GLuint textureTrash_v;
//output frame buffer object (GL -> video)
GLuint videoFBO;
GLuint videoDepthBuffer;
GLuint videoTexture;
GLuint videoTexture_u;
GLuint videoTexture_v;
gint outputWidth;
gint outputHeight;
GstVideoFormat outputVideo_format;
gpointer outputData;
GLenum multipleRT[3];
//from video to texture
gchar* textFProgram_YUY2_UYVY;
GLhandleARB GLSLProgram_YUY2;
GLhandleARB GLSLProgram_UYVY;
gchar* textFProgram_I420_YV12;
GLhandleARB GLSLProgram_I420_YV12;
gchar* textFProgram_AYUV;
GLhandleARB GLSLProgram_AYUV;
//from texture to video
gchar* textFProgram_to_YUY2_UYVY;
GLhandleARB GLSLProgram_to_YUY2;
GLhandleARB GLSLProgram_to_UYVY;
gchar* textFProgram_to_I420_YV12;
GLhandleARB GLSLProgram_to_I420_YV12;
gchar* textFProgram_to_AYUV;
GLhandleARB GLSLProgram_to_AYUV;
//client callbacks
CRCB clientReshapeCallback;
CDCB clientDrawCallback;
};
struct _GstGLDisplayClass {
GObjectClass object_class;
};
GType gst_gl_display_get_type (void);
//------------------------------------------------------------
//-------------------- Public déclarations ------------------
//------------------------------------------------------------
GstGLDisplay *gst_gl_display_new (void);
void gst_gl_display_initGLContext (GstGLDisplay* display,
GLint x, GLint y,
GLint graphic_width, GLint graphic_height,
GLint video_width, GLint video_height,
gulong winId,
gboolean visible);
void gst_gl_display_setClientReshapeCallback (GstGLDisplay* display, CRCB cb);
void gst_gl_display_setClientDrawCallback (GstGLDisplay* display, CDCB cb);
void gst_gl_display_setVisibleWindow (GstGLDisplay* display, gboolean visible);
void gst_gl_display_textureRequested (GstGLDisplay* display, GstVideoFormat format,
gint width, gint height, guint* texture,
guint* texture_u, guint* texture_v);
void gst_gl_display_textureChanged (GstGLDisplay* display, GstVideoFormat video_format,
GLuint texture, GLuint texture_u, GLuint texture_v,
gint width, gint height, gpointer data);
void gst_gl_display_clearTexture (GstGLDisplay* display, guint texture,
guint texture_u, guint texture_v);
void gst_gl_display_videoChanged (GstGLDisplay* display, GstVideoFormat video_format,
gpointer data);
void gst_gl_display_postRedisplay (GstGLDisplay* display);
void gst_gl_display_set_windowId (GstGLDisplay* display, gulong winId);
#endif

42
gst/gl/gstgl.c Normal file
View file

@ -0,0 +1,42 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* include gl filters headers */
#include "gstglgraphicmaker.h"
#include "gstglvideomaker.h"
#include "gstglimagesink.h"
#define GST_CAT_DEFAULT gst_gl_gstgl_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* Register filters that make up the gstgl plugin */
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_gl_gstgl_debug, "gstgl", 0, "gstgl");
if (!gst_element_register (plugin, "glvideomaker",
GST_RANK_NONE, GST_TYPE_GL_VIDEOMAKER)) {
return FALSE;
}
if (!gst_element_register (plugin, "glgraphicmaker",
GST_RANK_NONE, GST_TYPE_GL_GRAPHICMAKER)) {
return FALSE;
}
if (!gst_element_register (plugin, "glimagesink",
GST_RANK_NONE, GST_TYPE_GLIMAGE_SINK)) {
return FALSE;
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gstgl",
"OpenGL plugin",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

419
gst/gl/gstglgraphicmaker.c Normal file
View file

@ -0,0 +1,419 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglgraphicmaker.h"
#define GST_CAT_DEFAULT gst_gl_graphicmaker_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* inpect details */
static const GstElementDetails element_details = {
"glgraphicmaker",
"Transform filter",
"output an opengl scene flux",
"Jhonny Bravo and Kelly"
};
/* Source pad definition */
static GstStaticPadTemplate gst_gl_graphicmaker_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
);
/* Source pad definition */
static GstStaticPadTemplate gst_gl_graphicmaker_sink_pad_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";"
GST_VIDEO_CAPS_BGRx ";"
GST_VIDEO_CAPS_xRGB ";"
GST_VIDEO_CAPS_xBGR ";"
GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, AYUV }"))
);
/* Properties */
enum
{
PROP_0,
PROP_GLCONTEXT_WIDTH,
PROP_GLCONTEXT_HEIGHT,
PROP_CLIENT_RESHAPE_CALLBACK,
PROP_CLIENT_DRAW_CALLBACK
};
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (gst_gl_graphicmaker_debug, "glgraphicmaker", 0, "glgraphicmaker element");
GST_BOILERPLATE_FULL (GstGLGraphicmaker, gst_gl_graphicmaker, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
static void gst_gl_graphicmaker_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_graphicmaker_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_graphicmaker_reset (GstGLGraphicmaker* graphicmaker);
static gboolean gst_gl_graphicmaker_set_caps (GstBaseTransform * bt,
GstCaps * incaps, GstCaps * outcaps);
static GstCaps *gst_gl_graphicmaker_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps);
static gboolean gst_gl_graphicmaker_start (GstBaseTransform * bt);
static gboolean gst_gl_graphicmaker_stop (GstBaseTransform * bt);
static GstFlowReturn gst_gl_graphicmaker_prepare_output_buffer (GstBaseTransform *
trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
static GstFlowReturn gst_gl_graphicmaker_transform (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer * outbuf);
static gboolean gst_gl_graphicmaker_get_unit_size (GstBaseTransform * trans,
GstCaps * caps, guint * size);
static void
gst_gl_graphicmaker_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_set_details (element_class, &element_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_gl_graphicmaker_src_pad_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_gl_graphicmaker_sink_pad_template));
}
static void
gst_gl_graphicmaker_class_init (GstGLGraphicmakerClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_gl_graphicmaker_set_property;
gobject_class->get_property = gst_gl_graphicmaker_get_property;
GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
gst_gl_graphicmaker_transform_caps;
GST_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_graphicmaker_transform;
GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_graphicmaker_start;
GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_graphicmaker_stop;
GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_graphicmaker_set_caps;
GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_graphicmaker_get_unit_size;
GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer =
gst_gl_graphicmaker_prepare_output_buffer;
g_object_class_install_property (gobject_class, PROP_GLCONTEXT_WIDTH,
g_param_spec_int ("glcontext_width", "OpenGL context width",
"Change the opengl context width", 0, INT_MAX, 0,
G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, PROP_GLCONTEXT_HEIGHT,
g_param_spec_int ("glcontext_height", "OpenGL context height",
"Change the opengl context height", 0, INT_MAX, 0,
G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, PROP_CLIENT_RESHAPE_CALLBACK,
g_param_spec_pointer ("client_reshape_callback", "Client reshape callback",
"Executed in next glut loop iteration when window size is changed",
G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, PROP_CLIENT_DRAW_CALLBACK,
g_param_spec_pointer ("client_draw_callback", "Client draw callback",
"Executed in next glut loop iteration when glutPostRedisplay is called",
G_PARAM_WRITABLE));
}
static void
gst_gl_graphicmaker_init (GstGLGraphicmaker* graphicmaker, GstGLGraphicmakerClass * klass)
{
gst_gl_graphicmaker_reset (graphicmaker);
}
static void
gst_gl_graphicmaker_set_property (GObject* object, guint prop_id,
const GValue* value, GParamSpec* pspec)
{
GstGLGraphicmaker* graphicmaker = GST_GL_GRAPHICMAKER (object);
switch (prop_id) {
case PROP_GLCONTEXT_WIDTH:
{
graphicmaker->glcontext_width = g_value_get_int (value);
break;
}
case PROP_GLCONTEXT_HEIGHT:
{
graphicmaker->glcontext_height = g_value_get_int (value);
break;
}
case PROP_CLIENT_RESHAPE_CALLBACK:
{
graphicmaker->clientReshapeCallback = g_value_get_pointer (value);
break;
}
case PROP_CLIENT_DRAW_CALLBACK:
{
graphicmaker->clientDrawCallback = g_value_get_pointer (value);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_graphicmaker_get_property (GObject* object, guint prop_id,
GValue* value, GParamSpec* pspec)
{
//GstGLGraphicmaker *graphicmaker = GST_GL_GRAPHICMAKER (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_graphicmaker_reset (GstGLGraphicmaker* graphicmaker)
{
if (graphicmaker->display) {
g_object_unref (graphicmaker->display);
graphicmaker->display = NULL;
}
graphicmaker->peek = FALSE;
graphicmaker->glcontext_width = 0;
graphicmaker->glcontext_height = 0;
graphicmaker->clientReshapeCallback = NULL;
graphicmaker->clientDrawCallback = NULL;
}
static gboolean
gst_gl_graphicmaker_start (GstBaseTransform * bt)
{
GstGLGraphicmaker* graphicmaker = GST_GL_GRAPHICMAKER (bt);
return TRUE;
}
static gboolean
gst_gl_graphicmaker_stop (GstBaseTransform * bt)
{
GstGLGraphicmaker* graphicmaker = GST_GL_GRAPHICMAKER (bt);
gst_gl_graphicmaker_reset (graphicmaker);
return TRUE;
}
static GstCaps *
gst_gl_graphicmaker_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps)
{
GstGLGraphicmaker* graphicmaker;
GstStructure* structure;
GstCaps* newcaps, *newothercaps;
GstStructure* newstruct;
const GValue* width_value;
const GValue* height_value;
const GValue* framerate_value;
const GValue* par_value;
graphicmaker = GST_GL_GRAPHICMAKER (bt);
GST_ERROR ("transform caps %" GST_PTR_FORMAT, caps);
structure = gst_caps_get_structure (caps, 0);
width_value = gst_structure_get_value (structure, "width");
height_value = gst_structure_get_value (structure, "height");
framerate_value = gst_structure_get_value (structure, "framerate");
par_value = gst_structure_get_value (structure, "pixel-aspect-ratio");
if (direction == GST_PAD_SRC)
{
newothercaps = gst_caps_new_simple ("video/x-raw-rgb", NULL);
newstruct = gst_caps_get_structure (newothercaps, 0);
gst_structure_set_value (newstruct, "width", width_value);
gst_structure_set_value (newstruct, "height", height_value);
gst_structure_set_value (newstruct, "framerate", framerate_value);
if (par_value)
gst_structure_set_value (newstruct, "pixel-aspect-ratio", par_value);
else
gst_structure_set (newstruct, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1, 1, NULL);
newcaps = gst_caps_new_simple ("video/x-raw-yuv", NULL);
gst_caps_append(newcaps, newothercaps);
newstruct = gst_caps_get_structure (newcaps, 0);
gst_structure_set_value (newstruct, "width", width_value);
gst_structure_set_value (newstruct, "height", height_value);
}
else
{
newcaps = gst_caps_new_simple ("video/x-raw-gl", NULL);
newstruct = gst_caps_get_structure (newcaps, 0);
if (graphicmaker->glcontext_width != 0 && graphicmaker->glcontext_height != 0)
{
GValue value_w = { 0 };
GValue value_h = { 0 };
g_value_init (&value_w, G_TYPE_INT);
g_value_init (&value_h, G_TYPE_INT);
g_value_set_int (&value_w, graphicmaker->glcontext_width);
g_value_set_int (&value_h, graphicmaker->glcontext_height);
gst_structure_set_value (newstruct, "width", &value_w);
gst_structure_set_value (newstruct, "height", &value_h);
g_value_unset (&value_w);
g_value_unset (&value_h);
}
else
{
gst_structure_set_value (newstruct, "width", width_value);
gst_structure_set_value (newstruct, "height", height_value);
}
}
gst_structure_set_value (newstruct, "framerate", framerate_value);
if (par_value)
gst_structure_set_value (newstruct, "pixel-aspect-ratio", par_value);
else
gst_structure_set (newstruct, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1, 1, NULL);
GST_ERROR ("new caps %" GST_PTR_FORMAT, newcaps);
return newcaps;
}
static gboolean
gst_gl_graphicmaker_set_caps (GstBaseTransform* bt, GstCaps* incaps,
GstCaps* outcaps)
{
GstGLGraphicmaker* graphicmaker;
gboolean ret;
graphicmaker = GST_GL_GRAPHICMAKER (bt);
GST_DEBUG ("called with %" GST_PTR_FORMAT, incaps);
ret = gst_video_format_parse_caps (incaps, &graphicmaker->video_format,
&graphicmaker->width, &graphicmaker->height);
if (!ret) {
GST_DEBUG ("bad caps");
return FALSE;
}
graphicmaker->display = gst_gl_display_new ();
//client opengl context size
if (graphicmaker->glcontext_width != 0 && graphicmaker->glcontext_height != 0)
gst_gl_display_initGLContext (graphicmaker->display, 0, 0,
graphicmaker->glcontext_width, graphicmaker->glcontext_height,
graphicmaker->width, graphicmaker->height, 0, FALSE);
//default opengl context size
else
{
//init unvisible opengl context
static gint glcontext_y = 0;
gst_gl_display_initGLContext (graphicmaker->display,
50, glcontext_y++ * (graphicmaker->height+50) + 50,
graphicmaker->width, graphicmaker->height,
graphicmaker->width, graphicmaker->height, 0, FALSE);
}
//set the client reshape callback
gst_gl_display_setClientReshapeCallback (graphicmaker->display,
graphicmaker->clientReshapeCallback);
//set the client draw callback
gst_gl_display_setClientDrawCallback (graphicmaker->display,
graphicmaker->clientDrawCallback);
return ret;
}
static gboolean
gst_gl_graphicmaker_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
guint * size)
{
gboolean ret;
GstStructure *structure;
gint width;
gint height;
structure = gst_caps_get_structure (caps, 0);
if (gst_structure_has_name (structure, "video/x-raw-gl"))
{
GstVideoFormat video_format;
ret = gst_gl_buffer_format_parse_caps (caps, &video_format, &width, &height);
if (ret)
*size = gst_gl_buffer_format_get_size (video_format, width, height);
}
else
{
GstVideoFormat video_format;
ret = gst_video_format_parse_caps (caps, &video_format, &width, &height);
if (ret)
*size = gst_video_format_get_size (video_format, width, height);
}
return TRUE;
}
static GstFlowReturn
gst_gl_graphicmaker_prepare_output_buffer (GstBaseTransform* trans,
GstBuffer* input, gint size, GstCaps* caps, GstBuffer** buf)
{
GstGLGraphicmaker* graphicmaker;
GstGLBuffer* gl_outbuf;
graphicmaker = GST_GL_GRAPHICMAKER (trans);
//blocking call
//client opengl context size
if (graphicmaker->glcontext_width != 0 && graphicmaker->glcontext_height != 0)
gl_outbuf = gst_gl_buffer_new_from_video_format (graphicmaker->display,
graphicmaker->video_format,
graphicmaker->glcontext_width, graphicmaker->glcontext_height,
graphicmaker->width, graphicmaker->height);
//default opengl context size
else
gl_outbuf = gst_gl_buffer_new_from_video_format (graphicmaker->display,
graphicmaker->video_format,
graphicmaker->width, graphicmaker->height,
graphicmaker->width, graphicmaker->height);
*buf = GST_BUFFER (gl_outbuf);
gst_buffer_set_caps (*buf, caps);
return GST_FLOW_OK;
}
static GstFlowReturn
gst_gl_graphicmaker_transform (GstBaseTransform* trans, GstBuffer* inbuf,
GstBuffer* outbuf)
{
GstGLGraphicmaker* graphicmaker;
GstGLBuffer* gl_outbuf = GST_GL_BUFFER (outbuf);
graphicmaker = GST_GL_GRAPHICMAKER (trans);
GST_DEBUG ("making graphic %p size %d",
GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
//blocking call
gst_gl_display_textureChanged(graphicmaker->display, graphicmaker->video_format,
gl_outbuf->texture, gl_outbuf->texture_u, gl_outbuf->texture_v,
gl_outbuf->width, gl_outbuf->height, GST_BUFFER_DATA (inbuf));
return GST_FLOW_OK;
}

View file

@ -0,0 +1,52 @@
#ifndef _GST_GLGRAPHICMAKER_H_
#define _GST_GLGRAPHICMAKER_H_
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
#include "gstglbuffer.h"
G_BEGIN_DECLS
#define GST_TYPE_GL_GRAPHICMAKER (gst_gl_graphicmaker_get_type())
#define GST_GL_GRAPHICMAKER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_GRAPHICMAKER,GstGLGraphicmaker))
#define GST_IS_GL_GRAPHICMAKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_GRAPHICMAKER))
#define GST_GL_GRAPHICMAKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_GRAPHICMAKER,GstGLGraphicmakerClass))
#define GST_IS_GL_GRAPHICMAKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_GRAPHICMAKER))
#define GST_GL_GRAPHICMAKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_GRAPHICMAKER,GstGLGraphicmakerClass))
typedef struct _GstGLGraphicmaker GstGLGraphicmaker;
typedef struct _GstGLGraphicmakerClass GstGLGraphicmakerClass;
struct _GstGLGraphicmaker
{
GstBaseTransform base_transform;
GstPad *srcpad;
GstPad *sinkpad;
GstGLDisplay *display;
GstVideoFormat video_format;
gint width;
gint height;
gboolean peek;
gint glcontext_width;
gint glcontext_height;
CRCB clientReshapeCallback;
CDCB clientDrawCallback;
};
struct _GstGLGraphicmakerClass
{
GstBaseTransformClass base_transform_class;
};
GType gst_gl_graphicmaker_get_type (void);
G_END_DECLS
#endif /* _GST_GLGRAPHICMAKER_H_ */

517
gst/gl/gstglimagesink.c Normal file
View file

@ -0,0 +1,517 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/interfaces/xoverlay.h>
#include "gstglimagesink.h"
GST_DEBUG_CATEGORY (gst_debug_glimage_sink);
#define GST_CAT_DEFAULT gst_debug_glimage_sink
static void gst_glimage_sink_init_interfaces (GType type);
static void gst_glimage_sink_finalize (GObject * object);
static void gst_glimage_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * param_spec);
static void gst_glimage_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * param_spec);
static GstStateChangeReturn
gst_glimage_sink_change_state (GstElement * element, GstStateChange transition);
static void gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
GstClockTime * start, GstClockTime * end);
static GstCaps *gst_glimage_sink_get_caps (GstBaseSink * bsink);
static gboolean gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
static GstFlowReturn gst_glimage_sink_render (GstBaseSink * bsink,
GstBuffer * buf);
static gboolean gst_glimage_sink_start (GstBaseSink * bsink);
static gboolean gst_glimage_sink_stop (GstBaseSink * bsink);
static gboolean gst_glimage_sink_unlock (GstBaseSink * bsink);
static void gst_glimage_sink_xoverlay_init (GstXOverlayClass * iface);
static void gst_glimage_sink_set_xwindow_id (GstXOverlay * overlay,
gulong window_id);
static void gst_glimage_sink_expose (GstXOverlay * overlay);
static gboolean gst_glimage_sink_interface_supported (GstImplementsInterface *
iface, GType type);
static void gst_glimage_sink_implements_init (GstImplementsInterfaceClass *
klass);
static const GstElementDetails gst_glimage_sink_details =
GST_ELEMENT_DETAILS ("OpenGL video sink",
"Sink/Video",
"A videosink based on OpenGL",
"Julien Isorce <julien.isorce@gmail.com>");
static GstStaticPadTemplate gst_glimage_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_GL_VIDEO_CAPS ";"
GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
GST_VIDEO_CAPS_YUV ("{ YUY2, UYVY, AYUV, YV12, I420 }"))
);
enum
{
ARG_0,
ARG_DISPLAY
};
GST_BOILERPLATE_FULL (GstGLImageSink, gst_glimage_sink, GstVideoSink,
GST_TYPE_VIDEO_SINK, gst_glimage_sink_init_interfaces);
static void
gst_glimage_sink_init_interfaces (GType type)
{
static const GInterfaceInfo implements_info = {
(GInterfaceInitFunc) gst_glimage_sink_implements_init,
NULL,
NULL
};
static const GInterfaceInfo xoverlay_info = {
(GInterfaceInitFunc) gst_glimage_sink_xoverlay_init,
NULL,
NULL,
};
g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
&implements_info);
g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
}
static void
gst_glimage_sink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (element_class, &gst_glimage_sink_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_glimage_sink_template));
}
static void
gst_glimage_sink_class_init (GstGLImageSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gobject_class->set_property = gst_glimage_sink_set_property;
gobject_class->get_property = gst_glimage_sink_get_property;
g_object_class_install_property (gobject_class, ARG_DISPLAY,
g_param_spec_string ("display", "Display", "Display name",
NULL, G_PARAM_READWRITE));
gobject_class->finalize = gst_glimage_sink_finalize;
gstelement_class->change_state = gst_glimage_sink_change_state;
gstbasesink_class->set_caps = gst_glimage_sink_set_caps;
gstbasesink_class->get_times = gst_glimage_sink_get_times;
gstbasesink_class->preroll = gst_glimage_sink_render;
gstbasesink_class->render = gst_glimage_sink_render;
gstbasesink_class->start = gst_glimage_sink_start;
gstbasesink_class->stop = gst_glimage_sink_stop;
gstbasesink_class->unlock = gst_glimage_sink_unlock;
}
static void
gst_glimage_sink_init (GstGLImageSink * glimage_sink,
GstGLImageSinkClass * glimage_sink_class)
{
glimage_sink->display_name = NULL;
glimage_sink->window_id = 0;
glimage_sink->display = NULL;
glimage_sink->stored_buffer = NULL;
}
static void
gst_glimage_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLImageSink *glimage_sink;
g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
glimage_sink = GST_GLIMAGE_SINK (object);
switch (prop_id) {
case ARG_DISPLAY:
g_free (glimage_sink->display_name);
glimage_sink->display_name = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_glimage_sink_finalize (GObject * object)
{
GstGLImageSink *glimage_sink;
g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
glimage_sink = GST_GLIMAGE_SINK (object);
if (glimage_sink->caps) {
gst_caps_unref (glimage_sink->caps);
}
g_free (glimage_sink->display_name);
}
static void
gst_glimage_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLImageSink *glimage_sink;
g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
glimage_sink = GST_GLIMAGE_SINK (object);
switch (prop_id) {
case ARG_DISPLAY:
g_value_set_string (value, glimage_sink->display_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
* GstElement methods
*/
static GstStateChangeReturn
gst_glimage_sink_change_state (GstElement * element, GstStateChange transition)
{
GstGLImageSink *glimage_sink;
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG ("change state");
glimage_sink = GST_GLIMAGE_SINK (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* FIXME clear window */
glimage_sink->fps_n = 0;
glimage_sink->fps_d = 1;
GST_VIDEO_SINK_WIDTH (glimage_sink) = 0;
GST_VIDEO_SINK_HEIGHT (glimage_sink) = 0;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
/* FIXME dispose of window */
break;
default:
break;
}
return ret;
}
/*
* GstBaseSink methods
*/
static gboolean
gst_glimage_sink_start (GstBaseSink * bsink)
{
GstGLImageSink *glimage_sink;
GST_DEBUG ("start");
glimage_sink = GST_GLIMAGE_SINK (bsink);
/*if (glimage_sink->display && glimage_sink->window_id) {
gst_gl_display_set_window (glimage_sink->display, glimage_sink->window_id);
gst_gl_display_set_visible (glimage_sink->display, TRUE);
}*/
GST_DEBUG ("start done");
return TRUE;
}
static gboolean
gst_glimage_sink_stop (GstBaseSink * bsink)
{
GstGLImageSink *glimage_sink;
GST_DEBUG ("stop");
glimage_sink = GST_GLIMAGE_SINK (bsink);
if (glimage_sink->stored_buffer) {
gst_buffer_unref (glimage_sink->stored_buffer);
glimage_sink->stored_buffer = NULL;
}
if (glimage_sink->display) {
gst_gl_display_setVisibleWindow (glimage_sink->display, FALSE);
g_object_unref (glimage_sink->display);
glimage_sink->display = NULL;
}
return TRUE;
}
static gboolean
gst_glimage_sink_unlock (GstBaseSink * bsink)
{
//GstGLImageSink *glimage_sink;
GST_DEBUG ("unlock");
//glimage_sink = GST_GLIMAGE_SINK (bsink);
/* FIXME */
return TRUE;
}
static void
gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
GstClockTime * start, GstClockTime * end)
{
GstGLImageSink *glimagesink;
glimagesink = GST_GLIMAGE_SINK (bsink);
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
*start = GST_BUFFER_TIMESTAMP (buf);
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
*end = *start + GST_BUFFER_DURATION (buf);
} else {
if (glimagesink->fps_n > 0) {
*end = *start +
gst_util_uint64_scale_int (GST_SECOND, glimagesink->fps_d,
glimagesink->fps_n);
}
}
}
}
static gboolean
gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
GstGLImageSink *glimage_sink;
gint width;
gint height;
gboolean ok;
gint fps_n, fps_d;
gint par_n, par_d;
GstVideoFormat format;
GstStructure *structure;
gboolean is_gl;
GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
glimage_sink = GST_GLIMAGE_SINK (bsink);
structure = gst_caps_get_structure (caps, 0);
if (gst_structure_has_name (structure, "video/x-raw-gl")) {
is_gl = TRUE;
format = GST_VIDEO_FORMAT_UNKNOWN;
ok = gst_structure_get_int (structure, "width", &width);
ok &= gst_structure_get_int (structure, "height", &height);
} else {
is_gl = FALSE;
ok = gst_video_format_parse_caps (caps, &format, &width, &height);
}
ok &= gst_video_parse_caps_framerate (caps, &fps_n, &fps_d);
ok &= gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d);
if (!ok)
return FALSE;
GST_VIDEO_SINK_WIDTH (glimage_sink) = width;
GST_VIDEO_SINK_HEIGHT (glimage_sink) = height;
glimage_sink->is_gl = is_gl;
glimage_sink->format = format;
glimage_sink->width = width;
glimage_sink->height = height;
glimage_sink->fps_n = fps_n;
glimage_sink->fps_d = fps_d;
glimage_sink->par_n = par_n;
glimage_sink->par_d = par_d;
return TRUE;
}
static GstFlowReturn
gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
GstGLImageSink *glimage_sink = NULL;
GstGLBuffer *gl_buffer = NULL;
glimage_sink = GST_GLIMAGE_SINK (bsink);
//is gl
if (glimage_sink->is_gl)
{
//increment gl buffer ref before storage
gl_buffer = GST_GL_BUFFER (gst_buffer_ref (buf));
//if glimagesink has not the display yet
if (glimage_sink->display == NULL)
{
glimage_sink->display = g_object_ref (gl_buffer->display);
gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (glimage_sink));
if (glimage_sink->window_id)
gst_gl_display_set_windowId (glimage_sink->display, glimage_sink->window_id);
gst_gl_display_setVisibleWindow (glimage_sink->display, TRUE);
}
}
//is not gl
else
{
//if glimagesink has not the display yet
if (glimage_sink->display == NULL)
{
//do not stack when multiple windows
static gint glheight = 0;
//create a display
glimage_sink->display = gst_gl_display_new ();
//Notify application to set window id now
if (!glimage_sink->window_id)
gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (glimage_sink));
//init opengl context
gst_gl_display_initGLContext (glimage_sink->display,
50, glheight++ * (glimage_sink->height+50) + 50,
glimage_sink->width, glimage_sink->height,
glimage_sink->width, glimage_sink->height,
glimage_sink->window_id,
TRUE);
}
//blocking call
gl_buffer = gst_gl_buffer_new_from_video_format (glimage_sink->display,
glimage_sink->format, glimage_sink->width, glimage_sink->height,
glimage_sink->width, glimage_sink->height);
//blocking call
gst_gl_display_textureChanged(glimage_sink->display, glimage_sink->format,
gl_buffer->texture, gl_buffer->texture_u, gl_buffer->texture_v,
gl_buffer->width, gl_buffer->height, GST_BUFFER_DATA (buf));
//gl_buffer is created in this block, so the gl buffer is already referenced
}
//the buffer is cleared when an other comes in
if (glimage_sink->stored_buffer)
{
gst_buffer_unref (glimage_sink->stored_buffer);
glimage_sink->stored_buffer = NULL;
}
//store current buffer
glimage_sink->stored_buffer = gl_buffer;
//redisplay opengl scene
gst_gl_display_postRedisplay (glimage_sink->display);
return GST_FLOW_OK;
}
static void
gst_glimage_sink_xoverlay_init (GstXOverlayClass* iface)
{
iface->set_xwindow_id = gst_glimage_sink_set_xwindow_id;
iface->expose = gst_glimage_sink_expose;
}
static void
gst_glimage_sink_set_xwindow_id (GstXOverlay* overlay, gulong window_id)
{
GstGLImageSink* glimage_sink = GST_GLIMAGE_SINK (overlay);
g_return_if_fail (GST_IS_GLIMAGE_SINK (overlay));
g_assert (glimage_sink->display != NULL);
GST_DEBUG ("set_xwindow_id %ld", window_id);
if (glimage_sink->window_id == window_id)
return;
if (window_id)
{
//if (glimage_sink->window_id && ddrawsink->isInternal)
//close internal window
glimage_sink->window_id = window_id;
//gst_gl_display_set_windowId (glimage_sink->display, glimage_sink->window_id);
}
//Handle the case where window_id is 0 and we want the sink to
//create a new window when playback was already started (after set_caps)
}
static void
gst_glimage_sink_expose (GstXOverlay * overlay)
{
GstGLImageSink* glimage_sink = GST_GLIMAGE_SINK (overlay);
//redisplay opengl scene
if (glimage_sink->display)
gst_gl_display_postRedisplay (glimage_sink->display);
}
static gboolean
gst_glimage_sink_interface_supported (GstImplementsInterface * iface,
GType type)
{
return TRUE;
}
static void
gst_glimage_sink_implements_init (GstImplementsInterfaceClass * klass)
{
klass->supported = gst_glimage_sink_interface_supported;
}

59
gst/gl/gstglimagesink.h Normal file
View file

@ -0,0 +1,59 @@
#ifndef _GLIMAGESINK_H_
#define _GLIMAGESINK_H_
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include "gstglbuffer.h"
GST_DEBUG_CATEGORY_EXTERN (gst_debug_glimage_sink);
#define GST_TYPE_GLIMAGE_SINK \
(gst_glimage_sink_get_type())
#define GST_GLIMAGE_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GLIMAGE_SINK,GstGLImageSink))
#define GST_GLIMAGE_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GLIMAGE_SINK,GstGLImageSinkClass))
#define GST_IS_GLIMAGE_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GLIMAGE_SINK))
#define GST_IS_GLIMAGE_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GLIMAGE_SINK))
typedef struct _GstGLImageSink GstGLImageSink;
typedef struct _GstGLImageSinkClass GstGLImageSinkClass;
struct _GstGLImageSink
{
GstVideoSink video_sink;
//properties
gchar *display_name;
gulong window_id;
//gboolean isInternal;
//caps
GstCaps *caps;
GstVideoFormat format;
gint width;
gint height;
gboolean is_gl;
gint fps_n, fps_d;
gint par_n, par_d;
GstGLDisplay *display;
GstGLBuffer *stored_buffer;
};
struct _GstGLImageSinkClass
{
GstVideoSinkClass video_sink_class;
};
GType gst_glimage_sink_get_type(void);
#endif

289
gst/gl/gstglvideomaker.c Normal file
View file

@ -0,0 +1,289 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglvideomaker.h"
#define GST_CAT_DEFAULT gst_gl_videomaker_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
static const GstElementDetails element_details = GST_ELEMENT_DETAILS ("FIXME",
"Filter/Effect",
"FIXME example filter",
"FIXME <fixme@fixme.com>");
static GstStaticPadTemplate gst_gl_videomaker_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB ";"
GST_VIDEO_CAPS_RGBx ";"
GST_VIDEO_CAPS_BGRx ";"
GST_VIDEO_CAPS_xBGR ";"
GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, AYUV }"))
);
static GstStaticPadTemplate gst_gl_videomaker_sink_pad_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
);
enum
{
PROP_0
};
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (gst_gl_videomaker_debug, "glvideomaker", 0, "glvideomaker element");
GST_BOILERPLATE_FULL (GstGLVideomaker, gst_gl_videomaker, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
static void gst_gl_videomaker_set_property (GObject* object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_videomaker_get_property (GObject* object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_videomaker_reset (GstGLVideomaker* videomaker);
static gboolean gst_gl_videomaker_set_caps (GstBaseTransform* bt,
GstCaps* incaps, GstCaps* outcaps);
static GstCaps* gst_gl_videomaker_transform_caps (GstBaseTransform* bt,
GstPadDirection direction, GstCaps* caps);
static gboolean gst_gl_videomaker_start (GstBaseTransform* bt);
static gboolean gst_gl_videomaker_stop (GstBaseTransform* bt);
static GstFlowReturn gst_gl_videomaker_transform (GstBaseTransform* trans,
GstBuffer* inbuf, GstBuffer* outbuf);
static gboolean
gst_gl_videomaker_get_unit_size (GstBaseTransform* trans, GstCaps* caps,
guint* size);
static void
gst_gl_videomaker_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_set_details (element_class, &element_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_gl_videomaker_src_pad_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_gl_videomaker_sink_pad_template));
}
static void
gst_gl_videomaker_class_init (GstGLVideomakerClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_gl_videomaker_set_property;
gobject_class->get_property = gst_gl_videomaker_get_property;
GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
gst_gl_videomaker_transform_caps;
GST_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_videomaker_transform;
GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_videomaker_start;
GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_videomaker_stop;
GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_videomaker_set_caps;
GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
gst_gl_videomaker_get_unit_size;
}
static void
gst_gl_videomaker_init (GstGLVideomaker* videomaker, GstGLVideomakerClass* klass)
{
gst_gl_videomaker_reset (videomaker);
}
static void
gst_gl_videomaker_set_property (GObject* object, guint prop_id,
const GValue* value, GParamSpec* pspec)
{
//GstGLVideomaker *videomaker = GST_GL_VIDEOMAKER (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_videomaker_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//GstGLVideomaker *videomaker = GST_GL_VIDEOMAKER (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_videomaker_reset (GstGLVideomaker* videomaker)
{
if (videomaker->display) {
g_object_unref (videomaker->display);
videomaker->display = NULL;
}
}
static gboolean
gst_gl_videomaker_start (GstBaseTransform* bt)
{
GstGLVideomaker* videomaker = GST_GL_VIDEOMAKER (bt);
return TRUE;
}
static gboolean
gst_gl_videomaker_stop (GstBaseTransform* bt)
{
GstGLVideomaker* videomaker = GST_GL_VIDEOMAKER (bt);
gst_gl_videomaker_reset (videomaker);
return TRUE;
}
static GstCaps *
gst_gl_videomaker_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps)
{
GstGLVideomaker* videomaker;
GstStructure* structure;
GstCaps *newcaps, *newothercaps;
GstStructure* newstruct;
const GValue* width_value;
const GValue* height_value;
const GValue* framerate_value;
const GValue* par_value;
videomaker = GST_GL_VIDEOMAKER (bt);
GST_ERROR ("transform caps %" GST_PTR_FORMAT, caps);
structure = gst_caps_get_structure (caps, 0);
width_value = gst_structure_get_value (structure, "width");
height_value = gst_structure_get_value (structure, "height");
framerate_value = gst_structure_get_value (structure, "framerate");
par_value = gst_structure_get_value (structure, "pixel-aspect-ratio");
if (direction == GST_PAD_SINK)
{
newothercaps = gst_caps_new_simple ("video/x-raw-rgb", NULL);
newstruct = gst_caps_get_structure (newothercaps, 0);
gst_structure_set_value (newstruct, "width", width_value);
gst_structure_set_value (newstruct, "height", height_value);
gst_structure_set_value (newstruct, "framerate", framerate_value);
if (par_value)
gst_structure_set_value (newstruct, "pixel-aspect-ratio", par_value);
else
gst_structure_set (newstruct, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1, 1, NULL);
newcaps = gst_caps_new_simple ("video/x-raw-yuv", NULL);
gst_caps_append(newcaps, newothercaps);
}
else newcaps = gst_caps_new_simple ("video/x-raw-gl", NULL);
newstruct = gst_caps_get_structure (newcaps, 0);
gst_structure_set_value (newstruct, "width", width_value);
gst_structure_set_value (newstruct, "height", height_value);
gst_structure_set_value (newstruct, "framerate", framerate_value);
if (par_value)
gst_structure_set_value (newstruct, "pixel-aspect-ratio", par_value);
else
gst_structure_set (newstruct, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1, 1, NULL);
GST_ERROR ("new caps %" GST_PTR_FORMAT, newcaps);
return newcaps;
}
static gboolean
gst_gl_videomaker_set_caps (GstBaseTransform* bt, GstCaps* incaps,
GstCaps * outcaps)
{
GstGLVideomaker* videomaker;
gboolean ret;
videomaker = GST_GL_VIDEOMAKER (bt);
GST_DEBUG ("called with %" GST_PTR_FORMAT, incaps);
ret = gst_video_format_parse_caps (outcaps, &videomaker->video_format,
&videomaker->width, &videomaker->height);
if (!ret) {
GST_ERROR ("bad caps");
return FALSE;
}
return ret;
}
static gboolean
gst_gl_videomaker_get_unit_size (GstBaseTransform* trans, GstCaps* caps,
guint* size)
{
gboolean ret;
GstStructure *structure;
gint width;
gint height;
structure = gst_caps_get_structure (caps, 0);
if (gst_structure_has_name (structure, "video/x-raw-gl"))
{
GstVideoFormat video_format;
ret = gst_gl_buffer_format_parse_caps (caps, &video_format, &width, &height);
if (ret)
*size = gst_gl_buffer_format_get_size (video_format, width, height);
}
else
{
GstVideoFormat video_format;
ret = gst_video_format_parse_caps (caps, &video_format, &width, &height);
if (ret)
*size = gst_video_format_get_size (video_format, width, height);
}
return ret;
}
static GstFlowReturn
gst_gl_videomaker_transform (GstBaseTransform* trans, GstBuffer* inbuf,
GstBuffer* outbuf)
{
GstGLVideomaker* videomaker = NULL;
GstGLBuffer *gl_inbuf = GST_GL_BUFFER (inbuf);
videomaker = GST_GL_VIDEOMAKER (trans);
if (videomaker->display == NULL)
videomaker->display = g_object_ref (gl_inbuf->display);
else
g_assert (videomaker->display == gl_inbuf->display);
GST_DEBUG ("making video %p size %d",
GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
//blocking call
gst_gl_display_videoChanged(videomaker->display,
videomaker->video_format, GST_BUFFER_DATA (outbuf));
return GST_FLOW_OK;
}

47
gst/gl/gstglvideomaker.h Normal file
View file

@ -0,0 +1,47 @@
#ifndef _GST_GLVIDEOMAKER_H_
#define _GST_GLVIDEOMAKER_H_
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
#include "gstglbuffer.h"
G_BEGIN_DECLS
#define GST_TYPE_GL_VIDEOMAKER (gst_gl_videomaker_get_type())
#define GST_GL_VIDEOMAKER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIDEOMAKER,GstGLVideomaker))
#define GST_IS_GL_VIDEOMAKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIDEOMAKER))
#define GST_GL_VIDEOMAKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_VIDEOMAKER,GstGLVideomakerClass))
#define GST_IS_GL_VIDEOMAKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIDEOMAKER))
#define GST_GL_VIDEOMAKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIDEOMAKER,GstGLVideomakerClass))
typedef struct _GstGLVideomaker GstGLVideomaker;
typedef struct _GstGLVideomakerClass GstGLVideomakerClass;
//typedef void (*GstGLVideomakerProcessFunc) (GstGLVideomaker *, guint8 *, guint);
struct _GstGLVideomaker
{
GstBaseTransform base_transform;
GstGLDisplay *display;
GstVideoFormat video_format;
gint width;
gint height;
};
struct _GstGLVideomakerClass
{
GstBaseTransformClass base_transform_class;
};
typedef struct _GstGLVideomaker GstGLVideomaker;
typedef struct _GstGLVideomakerClass GstGLVideomakerClass;
GType gst_gl_videomaker_get_type (void);
G_END_DECLS
#endif /* _GST_GLVIDEOMAKER_H_ */