mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-12 10:25:33 +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