mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-12 18:35:35 +00:00
[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:
parent
f1744c26ec
commit
a5ff5ff14e
11 changed files with 3707 additions and 0 deletions
124
gst-libs/gst/gl/gstglbuffer.c
Normal file
124
gst-libs/gst/gl/gstglbuffer.c
Normal 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;
|
||||||
|
}
|
54
gst-libs/gst/gl/gstglbuffer.h
Normal file
54
gst-libs/gst/gl/gstglbuffer.h
Normal 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
|
||||||
|
|
1909
gst-libs/gst/gl/gstgldisplay.c
Normal file
1909
gst-libs/gst/gl/gstgldisplay.c
Normal file
File diff suppressed because it is too large
Load diff
195
gst-libs/gst/gl/gstgldisplay.h
Normal file
195
gst-libs/gst/gl/gstgldisplay.h
Normal 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
42
gst/gl/gstgl.c
Normal 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
419
gst/gl/gstglgraphicmaker.c
Normal 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;
|
||||||
|
}
|
52
gst/gl/gstglgraphicmaker.h
Normal file
52
gst/gl/gstglgraphicmaker.h
Normal 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
517
gst/gl/gstglimagesink.c
Normal 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
59
gst/gl/gstglimagesink.h
Normal 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
289
gst/gl/gstglvideomaker.c
Normal 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
47
gst/gl/gstglvideomaker.h
Normal 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_ */
|
Loading…
Reference in a new issue