diff --git a/gst-libs/gst/gl/glextensions.c b/gst-libs/gst/gl/glextensions.c index 6926a970e0..ccf557261f 100644 --- a/gst-libs/gst/gl/glextensions.c +++ b/gst-libs/gst/gl/glextensions.c @@ -49,6 +49,7 @@ DEFINE_FUNC_RET (glCreateShaderObjectARB, GLhandleARB, (GLenum shaderType), (shaderType)); #if 0 typedef GLhandleARB type_glCreateShaderObjectARB (GLenum shaderType); + GLhandleARB glCreateShaderObjectARB (GLenum shaderType) { @@ -181,3 +182,8 @@ DEFINE_FUNC (glGetFramebufferAttachmentParameterivEXT, (GLenum target, DEFINE_FUNC (glGenerateMipmapEXT, (GLenum target), (target)); DEFINE_FUNC (glWindowPos2iARB, (GLint x, GLint y), (x, y)); + +DEFINE_FUNC (glGenProgramsARB, (GLsizei a, GLuint * b), (a, b)); +DEFINE_FUNC (glBindProgramARB, (GLenum a, GLuint b), (a, b)); +DEFINE_FUNC (glProgramStringARB, + (GLenum a, GLenum b, GLsizei c, const GLvoid * d), (a, b, c, d)); diff --git a/gst-libs/gst/gl/glextensions.h b/gst-libs/gst/gl/glextensions.h index 7ef01869d5..e161b8c444 100644 --- a/gst-libs/gst/gl/glextensions.h +++ b/gst-libs/gst/gl/glextensions.h @@ -56,5 +56,9 @@ void glGenerateMipmapEXT (GLenum target); void glWindowPos2iARB (GLint x, GLint y); +void glGenProgramsARB (GLsizei, GLuint *); +void glBindProgramARB (GLenum, GLuint); +void glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *); + #endif diff --git a/gst-libs/gst/gl/gstglbuffer.c b/gst-libs/gst/gl/gstglbuffer.c index 7a217a36a8..c1d5bb7bbd 100644 --- a/gst-libs/gst/gl/gstglbuffer.c +++ b/gst-libs/gst/gl/gstglbuffer.c @@ -77,11 +77,24 @@ gst_gl_buffer_get_type (void) GstGLBuffer * -gst_gl_buffer_new (GstGLDisplay * display, GstGLBufferFormat format, - int width, int height) +gst_gl_buffer_new (GstGLDisplay * display, int width, int height) +{ + g_return_val_if_fail (display != NULL, NULL); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + return gst_gl_buffer_new_with_format (display, GST_GL_BUFFER_FORMAT_RGBA, + width, height); +} + +GstGLBuffer * +gst_gl_buffer_new_with_format (GstGLDisplay * display, + GstGLBufferFormat format, int width, int height) { GstGLBuffer *buffer; + g_return_val_if_fail (format != GST_GL_BUFFER_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); @@ -90,9 +103,9 @@ gst_gl_buffer_new (GstGLDisplay * display, GstGLBufferFormat format, buffer->display = g_object_ref (display); buffer->width = width; buffer->height = height; - /* this is not strictly true, but it's used for compatibility with - * queue and BaseTransform */ - GST_BUFFER_SIZE (buffer) = width * height * 4; + buffer->format = format; + GST_BUFFER_SIZE (buffer) = gst_gl_buffer_format_get_size (format, width, + height); gst_gl_display_lock (buffer->display); glGenTextures (1, &buffer->texture); @@ -100,11 +113,69 @@ gst_gl_buffer_new (GstGLDisplay * display, GstGLBufferFormat format, switch (format) { case GST_GL_BUFFER_FORMAT_RGBA: glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - buffer->width, buffer->height, 0, GL_RGBA, GL_FLOAT, NULL); + buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); break; case GST_GL_BUFFER_FORMAT_RGB: glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, - buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + buffer->width, buffer->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + break; + case GST_GL_BUFFER_FORMAT_YUYV: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA, + buffer->width, buffer->height, + 0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, NULL); + break; + case GST_GL_BUFFER_FORMAT_PLANAR444: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + buffer->width, buffer->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &buffer->texture_u); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_u); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + buffer->width, buffer->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &buffer->texture_v); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_v); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + buffer->width, buffer->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + break; + case GST_GL_BUFFER_FORMAT_PLANAR422: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + buffer->width, buffer->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &buffer->texture_u); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_u); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + GST_ROUND_UP_2 (buffer->width) / 2, buffer->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &buffer->texture_v); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_v); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + GST_ROUND_UP_2 (buffer->width) / 2, buffer->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + break; + case GST_GL_BUFFER_FORMAT_PLANAR420: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + buffer->width, buffer->height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &buffer->texture_u); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_u); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + GST_ROUND_UP_2 (buffer->width) / 2, + GST_ROUND_UP_2 (buffer->height) / 2, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &buffer->texture_v); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_v); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + GST_ROUND_UP_2 (buffer->width) / 2, + GST_ROUND_UP_2 (buffer->height) / 2, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); break; default: g_warning ("GL buffer format not handled"); @@ -116,138 +187,135 @@ gst_gl_buffer_new (GstGLDisplay * display, GstGLBufferFormat format, } GstGLBuffer * -gst_gl_buffer_new_from_data (GstGLDisplay * display, GstVideoFormat format, - int width, int height, void *data) +gst_gl_buffer_new_from_video_format (GstGLDisplay * display, + GstVideoFormat video_format, int width, int height) { GstGLBuffer *buffer; - int comp; g_return_val_if_fail (width > 0, NULL); g_return_val_if_fail (height > 0, NULL); - g_return_val_if_fail (data != NULL, NULL); + + buffer = gst_gl_buffer_new_with_format (display, + gst_gl_buffer_format_from_video_format (video_format), width, height); + + switch (video_format) { + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_xBGR: + buffer->is_yuv = FALSE; + break; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + /* counterintuitive: when you use a GL_YCBCR_MESA texture, the + * colorspace is automatically converted, so it's referred to + * as RGB */ + buffer->is_yuv = FALSE; + break; + case GST_VIDEO_FORMAT_AYUV: + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + buffer->is_yuv = TRUE; + break; + default: + g_assert_not_reached (); + } + + return buffer; +} + +void +gst_gl_buffer_upload (GstGLBuffer * buffer, GstVideoFormat video_format, + void *data) +{ + int width = buffer->width; + int height = buffer->height; GST_DEBUG ("uploading %p %dx%d", data, width, height); - buffer = (GstGLBuffer *) gst_mini_object_new (GST_TYPE_GL_BUFFER); - buffer->display = g_object_ref (display); - buffer->width = width; - buffer->height = height; - /* this is not strictly true, but it's used for compatibility with - * queue and BaseTransform */ - GST_BUFFER_SIZE (buffer) = width * height * 4; + g_return_if_fail (buffer->format == + gst_gl_buffer_format_from_video_format (video_format)); gst_gl_display_lock (buffer->display); - glGenTextures (1, &buffer->texture); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture); - switch (format) { + switch (video_format) { case GST_VIDEO_FORMAT_RGBx: - buffer->format = GST_GL_BUFFER_FORMAT_RGB; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); break; case GST_VIDEO_FORMAT_BGRx: - buffer->format = GST_GL_BUFFER_FORMAT_RGB; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, data); break; + case GST_VIDEO_FORMAT_AYUV: case GST_VIDEO_FORMAT_xRGB: - buffer->format = GST_GL_BUFFER_FORMAT_RGB; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, data); break; case GST_VIDEO_FORMAT_xBGR: - buffer->format = GST_GL_BUFFER_FORMAT_RGB; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, data); break; case GST_VIDEO_FORMAT_YUY2: - buffer->format = GST_GL_BUFFER_FORMAT_YUYV; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA, width, height, - 0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, NULL); glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, data); break; case GST_VIDEO_FORMAT_UYVY: - buffer->format = GST_GL_BUFFER_FORMAT_YUYV; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA, width, height, - 0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, NULL); glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, data); break; - case GST_VIDEO_FORMAT_AYUV: - buffer->format = GST_GL_BUFFER_FORMAT_RGB; - buffer->is_yuv = TRUE; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, data); - break; case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_YV12: - buffer->format = GST_GL_BUFFER_FORMAT_PLANAR420; - buffer->is_yuv = TRUE; - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, - buffer->width, buffer->height, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); - glGenTextures (1, &buffer->texture_u); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_u); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, - GST_ROUND_UP_2 (buffer->width) / 2, - GST_ROUND_UP_2 (buffer->height) / 2, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); - comp = (format == GST_VIDEO_FORMAT_I420) ? 1 : 2; glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, GST_ROUND_UP_2 (buffer->width) / 2, GST_ROUND_UP_2 (buffer->height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE, (guint8 *) data + - gst_video_format_get_component_offset (format, comp, width, height)); + gst_video_format_get_component_offset (video_format, 1, width, + height)); - glGenTextures (1, &buffer->texture_v); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_v); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, - GST_ROUND_UP_2 (buffer->width) / 2, - GST_ROUND_UP_2 (buffer->height) / 2, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); - comp = (format == GST_VIDEO_FORMAT_I420) ? 2 : 1; glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, GST_ROUND_UP_2 (buffer->width) / 2, GST_ROUND_UP_2 (buffer->height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE, (guint8 *) data + - gst_video_format_get_component_offset (format, comp, width, height)); + gst_video_format_get_component_offset (video_format, 2, width, + height)); break; default: g_assert_not_reached (); } gst_gl_display_unlock (buffer->display); - - return buffer; } void -gst_gl_buffer_download (GstGLBuffer * buffer, GstVideoFormat format, void *data) +gst_gl_buffer_download (GstGLBuffer * buffer, GstVideoFormat video_format, + void *data) { GLuint fbo; + g_return_if_fail (buffer->format == + gst_gl_buffer_format_from_video_format (video_format)); + GST_DEBUG ("downloading"); gst_gl_display_lock (buffer->display); + /* we need a reset function */ + glMatrixMode (GL_COLOR); + glLoadIdentity (); + glPixelTransferf (GL_POST_COLOR_MATRIX_RED_BIAS, 0); + glPixelTransferf (GL_POST_COLOR_MATRIX_GREEN_BIAS, 0); + glPixelTransferf (GL_POST_COLOR_MATRIX_BLUE_BIAS, 0); + glGenFramebuffersEXT (1, &fbo); glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo); @@ -260,14 +328,7 @@ gst_gl_buffer_download (GstGLBuffer * buffer, GstVideoFormat format, void *data) g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT); - /* we need a reset function */ - glMatrixMode (GL_COLOR); - glLoadIdentity (); - glPixelTransferf (GL_POST_COLOR_MATRIX_RED_BIAS, 0); - glPixelTransferf (GL_POST_COLOR_MATRIX_GREEN_BIAS, 0); - glPixelTransferf (GL_POST_COLOR_MATRIX_BLUE_BIAS, 0); - - switch (format) { + switch (video_format) { case GST_VIDEO_FORMAT_RGBx: glReadPixels (0, 0, buffer->width, buffer->height, GL_RGBA, GL_UNSIGNED_BYTE, data); @@ -280,10 +341,42 @@ gst_gl_buffer_download (GstGLBuffer * buffer, GstVideoFormat format, void *data) glReadPixels (0, 0, buffer->width, buffer->height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, data); break; + case GST_VIDEO_FORMAT_AYUV: case GST_VIDEO_FORMAT_xRGB: glReadPixels (0, 0, buffer->width, buffer->height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, data); break; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + g_warning ("video format not supported for download from GL texture"); + break; + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + glReadPixels (0, 0, buffer->width, buffer->height, + GL_LUMINANCE, GL_UNSIGNED_BYTE, data); + + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, + buffer->texture_u, 0); + glReadPixels (0, 0, + GST_ROUND_UP_2 (buffer->width) / 2, + GST_ROUND_UP_2 (buffer->height) / 2, + GL_LUMINANCE, GL_UNSIGNED_BYTE, + (guint8 *) data + + gst_video_format_get_component_offset (video_format, 1, buffer->width, + buffer->height)); + + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, + buffer->texture_v, 0); + glReadPixels (0, 0, + GST_ROUND_UP_2 (buffer->width) / 2, + GST_ROUND_UP_2 (buffer->height) / 2, + GL_LUMINANCE, GL_UNSIGNED_BYTE, + (guint8 *) data + + gst_video_format_get_component_offset (video_format, 2, buffer->width, + buffer->height)); + break; default: g_assert_not_reached (); } @@ -292,3 +385,67 @@ gst_gl_buffer_download (GstGLBuffer * buffer, GstVideoFormat format, void *data) gst_gl_display_unlock (buffer->display); } + + + +/* buffer format */ + +GstGLBufferFormat +gst_gl_buffer_format_from_video_format (GstVideoFormat format) +{ + switch (format) { + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_xBGR: + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_BGRA: + case GST_VIDEO_FORMAT_ARGB: + case GST_VIDEO_FORMAT_ABGR: + case GST_VIDEO_FORMAT_AYUV: + return GST_GL_BUFFER_FORMAT_RGBA; + case GST_VIDEO_FORMAT_RGB: + case GST_VIDEO_FORMAT_BGR: + return GST_GL_BUFFER_FORMAT_RGB; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + return GST_GL_BUFFER_FORMAT_YUYV; + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + return GST_GL_BUFFER_FORMAT_PLANAR420; + case GST_VIDEO_FORMAT_UNKNOWN: + return GST_GL_BUFFER_FORMAT_UNKNOWN; + } + + g_return_val_if_reached (GST_GL_BUFFER_FORMAT_UNKNOWN); +} + +int +gst_gl_buffer_format_get_size (GstGLBufferFormat 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, GstGLBufferFormat * format, + int *width, int *height) +{ + GstStructure *structure; + int format_as_int; + 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, "format", &format_as_int); + *format = format_as_int; + ret &= gst_structure_get_int (structure, "width", width); + ret &= gst_structure_get_int (structure, "height", height); + + return ret; +} diff --git a/gst-libs/gst/gl/gstglbuffer.h b/gst-libs/gst/gl/gstglbuffer.h index e5a39441f4..cf2e014154 100644 --- a/gst-libs/gst/gl/gstglbuffer.h +++ b/gst-libs/gst/gl/gstglbuffer.h @@ -14,6 +14,7 @@ typedef struct _GstGLBuffer GstGLBuffer; #define GST_GL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_BUFFER, GstGLBuffer)) typedef enum { + GST_GL_BUFFER_FORMAT_UNKNOWN, GST_GL_BUFFER_FORMAT_RGBA, GST_GL_BUFFER_FORMAT_RGB, GST_GL_BUFFER_FORMAT_YUYV, @@ -41,21 +42,32 @@ struct _GstGLBuffer { GType gst_gl_buffer_get_type (void); GstGLBuffer * gst_gl_buffer_new (GstGLDisplay *display, + int width, int height); +GstGLBuffer * gst_gl_buffer_new_with_format (GstGLDisplay *display, GstGLBufferFormat format, int width, int height); -GstGLBuffer * gst_gl_buffer_new_from_data (GstGLDisplay *display, - GstVideoFormat format, int width, int height, void *data); +GstGLBuffer * gst_gl_buffer_new_from_video_format (GstGLDisplay *display, + GstVideoFormat format, int width, int height); +void gst_gl_buffer_upload (GstGLBuffer *buffer, + GstVideoFormat format, void *data); void gst_gl_buffer_download (GstGLBuffer *buffer, GstVideoFormat format, void *data); #define GST_GL_VIDEO_CAPS \ "video/x-raw-gl," \ - "format=(int)[0,10]," \ + "format=(int)1," \ + "is_yuv=(boolean)FALSE," \ "width=(int)[1,2048]," \ "height=(int)[1,2048]," \ "pixel-aspect-ratio=(fraction)1/1," \ "framerate=(fraction)[0/1,100/1]" +GstGLBufferFormat gst_gl_buffer_format_from_video_format (GstVideoFormat format); +int gst_gl_buffer_format_get_size (GstGLBufferFormat format, int width, + int height); +gboolean gst_gl_buffer_format_parse_caps (GstCaps *caps, GstGLBufferFormat *format, + int *width, int *height); + #endif diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index 6d93c8896e..f0995c1bca 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -57,15 +57,17 @@ gst_gl_display_finalize (GObject * object) { GstGLDisplay *display = GST_GL_DISPLAY (object); - if (display->assigned_window == None) { + GST_DEBUG ("finalize %p", object); + + if (display->window != None) { XDestroyWindow (display->display, display->window); } if (display->context) { glXDestroyContext (display->display, display->context); } - if (display->visinfo) { - XFree (display->visinfo); - } + //if (display->visinfo) { + // XFree (display->visinfo); + //} if (display->display) { XCloseDisplay (display->display); } @@ -165,11 +167,28 @@ gst_gl_display_check_features (GstGLDisplay * display) GST_DEBUG ("No GLX extension"); return FALSE; } +#if 0 + { + int i; + int n; - visinfo = glXChooseVisual (display->display, scrnum, attrib); - if (visinfo == NULL) { - GST_DEBUG ("No usable visual"); - return FALSE; + visinfo = XGetVisualInfo (display->display, 0, NULL, &n); + for (i = 0; i < n; i++) { + GST_ERROR ("%d: %d %ld", i, visinfo[i].depth, visinfo[i].visualid); + if (visinfo[i].depth == 32) + break; + } + + visinfo += i; + } +#endif + + if (1) { + visinfo = glXChooseVisual (display->display, scrnum, attrib); + if (visinfo == NULL) { + GST_DEBUG ("No usable visual"); + return FALSE; + } } display->visinfo = visinfo; @@ -185,6 +204,8 @@ gst_gl_display_check_features (GstGLDisplay * display) mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect; + GST_ERROR ("creating window with visual %ld", visinfo->visualid); + window = XCreateWindow (display->display, root, 0, 0, 100, 100, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr); @@ -245,8 +266,16 @@ gst_gl_display_can_handle_type (GstGLDisplay * display, GstVideoFormat type) void gst_gl_display_lock (GstGLDisplay * display) { + gboolean ret; + + g_assert (display->window != None); + g_assert (display->context != NULL); + g_mutex_lock (display->lock); - glXMakeCurrent (display->display, display->window, display->context); + ret = glXMakeCurrent (display->display, display->window, display->context); + if (!ret) { + g_warning ("glxMakeCurrent failed"); + } gst_gl_display_check_error (display, __LINE__); } @@ -265,7 +294,10 @@ gst_gl_display_init_tmp_window (GstGLDisplay * display) int scrnum; int mask; Window root; + Window parent_window; Screen *screen; + int width; + int height; GST_DEBUG ("creating temp window"); @@ -277,20 +309,29 @@ gst_gl_display_init_tmp_window (GstGLDisplay * display) attr.border_pixel = 0; attr.colormap = XCreateColormap (display->display, root, display->visinfo->visual, AllocNone); - attr.override_redirect = False; -#if 0 - if (display->parent_window) { + if (display->parent_window != None) { + XWindowAttributes parent_attr; + attr.override_redirect = True; + parent_window = display->parent_window; + + XGetWindowAttributes (display->display, parent_window, &parent_attr); + width = parent_attr.width; + height = parent_attr.height; + } else { + attr.override_redirect = False; + parent_window = root; + width = 100; + height = 100; } -#endif mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect; display->window = XCreateWindow (display->display, - root, 0, 0, 100, 100, + parent_window, 0, 0, width, height, 0, display->visinfo->depth, InputOutput, display->visinfo->visual, mask, &attr); - //XMapWindow (display->display, display->window); + XMapWindow (display->display, display->window); XSync (display->display, FALSE); } @@ -305,6 +346,7 @@ gst_gl_display_set_window (GstGLDisplay * display, Window window) { g_mutex_lock (display->lock); +#if 0 if (window != display->assigned_window) { if (display->assigned_window == None) { gst_gl_display_destroy_tmp_window (display); @@ -316,6 +358,18 @@ gst_gl_display_set_window (GstGLDisplay * display, Window window) display->window = window; } } +#else + if (window != display->parent_window) { + gst_gl_display_destroy_tmp_window (display); + + display->parent_window = window; + + gst_gl_display_init_tmp_window (display); + + //XReparentWindow (display->display, display->window, + // display->assigned_window, 0, 0); + } +#endif g_mutex_unlock (display->lock); } @@ -327,6 +381,10 @@ gst_gl_display_update_attributes (GstGLDisplay * display) if (display->window != None) { XGetWindowAttributes (display->display, display->window, &attr); + + GST_DEBUG ("window visual %ld display visual %ld", + attr.visual->visualid, display->visinfo->visual->visualid); + display->win_width = attr.width; display->win_height = attr.height; } else { @@ -670,7 +728,7 @@ gst_gl_display_draw_image (GstGLDisplay * display, GstVideoFormat type, gst_gl_display_update_attributes (display); - //glXSwapIntervalSGI (1); + glXSwapIntervalSGI (1); glViewport (0, 0, display->win_width, display->win_height); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/gst-libs/gst/gl/gstgldisplay.h b/gst-libs/gst/gl/gstgldisplay.h index 677c569f28..907f2c8f26 100644 --- a/gst-libs/gst/gl/gstgldisplay.h +++ b/gst-libs/gst/gl/gstgldisplay.h @@ -46,7 +46,8 @@ struct _GstGLDisplay { gboolean have_color_matrix; Window window; - Window assigned_window; + //Window assigned_window; + Window parent_window; int win_width; int win_height; diff --git a/gst/gl/glimagesink.c b/gst/gl/glimagesink.c index 879790d780..365e4c4e49 100644 --- a/gst/gl/glimagesink.c +++ b/gst/gl/glimagesink.c @@ -301,11 +301,11 @@ gst_glimage_sink_start (GstBaseSink * bsink) GST_ERROR ("failed to open display"); return FALSE; } +#endif - if (glimage_sink->window_id) { + if (glimage_sink->display && glimage_sink->window_id) { gst_gl_display_set_window (glimage_sink->display, glimage_sink->window_id); } -#endif GST_DEBUG ("start done"); @@ -321,9 +321,10 @@ gst_glimage_sink_stop (GstBaseSink * bsink) glimage_sink = GST_GLIMAGE_SINK (bsink); - g_object_unref (glimage_sink->display); - - glimage_sink->display = NULL; + if (glimage_sink->display) { + g_object_unref (glimage_sink->display); + glimage_sink->display = NULL; + } return TRUE; } @@ -417,14 +418,6 @@ gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) glimage_sink->par_n = par_n; glimage_sink->par_d = par_d; - //glimage_sink->type = format; - -#if 0 - if (!glimage_sink->window) { - gst_glimage_sink_create_window (glimage_sink); - } -#endif - return TRUE; } @@ -441,21 +434,23 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) if (glimage_sink->display == NULL) { glimage_sink->display = g_object_ref (gl_buffer->display); +#if 1 if (glimage_sink->window_id) { gst_gl_display_set_window (glimage_sink->display, glimage_sink->window_id); } +#endif } else { g_assert (gl_buffer->display == glimage_sink->display); } display = gl_buffer->display; - gst_gl_display_lock (display); - /* FIXME polling causes a round-trip delay. This should be changed * to catch structure events */ gst_gl_display_update_attributes (display); + + gst_gl_display_lock (display); glViewport (0, 0, display->win_width, display->win_height); glClearColor (0.3, 0.3, 0.3, 1.0); @@ -519,7 +514,7 @@ gst_glimage_sink_set_xwindow_id (GstXOverlay * overlay, XID window_id) g_return_if_fail (GST_IS_GLIMAGE_SINK (overlay)); - GST_DEBUG ("set_xwindow_id"); + GST_DEBUG ("set_xwindow_id %ld", window_id); glimage_sink = GST_GLIMAGE_SINK (overlay); diff --git a/gst/gl/glimagesink.h b/gst/gl/glimagesink.h index 3467c619d4..3a5effe917 100644 --- a/gst/gl/glimagesink.h +++ b/gst/gl/glimagesink.h @@ -58,7 +58,6 @@ struct _GstGLImageSink int par_n, par_d; GstGLDisplay *display; - GstVideoFormat type; XID window_id; }; diff --git a/gst/gl/gstglconvert.c b/gst/gl/gstglconvert.c index 57daec5a5b..f4f525e97e 100644 --- a/gst/gl/gstglconvert.c +++ b/gst/gl/gstglconvert.c @@ -58,24 +58,6 @@ static const GstElementDetails element_details = GST_ELEMENT_DETAILS ("FIXME", "FIXME GL conversion filter", "FIXME "); -#if 0 -#define GST_GL_VIDEO_CAPS "video/x-raw-gl" - -static GstStaticPadTemplate gst_gl_convert_src_pad_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_GL_VIDEO_CAPS) - ); - -static GstStaticPadTemplate gst_gl_convert_sink_pad_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_GL_VIDEO_CAPS) - ); -#endif - enum { PROP_0 @@ -92,11 +74,8 @@ static void gst_gl_convert_set_property (GObject * object, guint prop_id, static void gst_gl_convert_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_gl_convert_reset (GstGLConvert * filter); -static gboolean gst_gl_convert_transform (GstGLFilter * filter, - GstGLBuffer * outbuf, GstGLBuffer * inbuf); -static gboolean gst_gl_convert_start (GstGLFilter * _filter); -static gboolean gst_gl_convert_stop (GstGLFilter * _filter); +static gboolean gst_gl_convert_filter (GstGLFilter * filter, + GstGLBuffer * inbuf, GstGLBuffer * outbuf); static void @@ -105,13 +84,6 @@ gst_gl_convert_base_init (gpointer klass) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_set_details (element_class, &element_details); - -#if 0 - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_gl_convert_src_pad_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_gl_convert_sink_pad_template)); -#endif } static void @@ -123,15 +95,12 @@ gst_gl_convert_class_init (GstGLConvertClass * klass) gobject_class->set_property = gst_gl_convert_set_property; gobject_class->get_property = gst_gl_convert_get_property; - GST_GL_FILTER_CLASS (klass)->transform = gst_gl_convert_transform; - GST_GL_FILTER_CLASS (klass)->start = gst_gl_convert_start; - GST_GL_FILTER_CLASS (klass)->stop = gst_gl_convert_stop; + GST_GL_FILTER_CLASS (klass)->filter = gst_gl_convert_filter; } static void gst_gl_convert_init (GstGLConvert * filter, GstGLConvertClass * klass) { - gst_gl_convert_reset (filter); } static void @@ -160,33 +129,9 @@ gst_gl_convert_get_property (GObject * object, guint prop_id, } } -static void -gst_gl_convert_reset (GstGLConvert * filter) -{ - -} - static gboolean -gst_gl_convert_start (GstGLFilter * _filter) -{ - //GstGLConvert *convert = GST_GL_CONVERT(_filter); - - return TRUE; -} - -static gboolean -gst_gl_convert_stop (GstGLFilter * _filter) -{ - GstGLConvert *convert = GST_GL_CONVERT (_filter); - - gst_gl_convert_reset (convert); - - return TRUE; -} - -static gboolean -gst_gl_convert_transform (GstGLFilter * filter, GstGLBuffer * outbuf, - GstGLBuffer * inbuf) +gst_gl_convert_filter (GstGLFilter * filter, GstGLBuffer * inbuf, + GstGLBuffer * outbuf) { //GstGLConvert *convert = GST_GL_CONVERT(filter); diff --git a/gst/gl/gstgldownload.c b/gst/gl/gstgldownload.c index b5a3f1b2dd..4c460b9b31 100644 --- a/gst/gl/gstgldownload.c +++ b/gst/gl/gstgldownload.c @@ -217,6 +217,8 @@ gst_gl_download_transform_caps (GstBaseTransform * bt, download = GST_GL_DOWNLOAD (bt); + GST_ERROR ("transform caps %" GST_PTR_FORMAT, caps); + structure = gst_caps_get_structure (caps, 0); width_value = gst_structure_get_value (structure, "width"); @@ -227,7 +229,9 @@ gst_gl_download_transform_caps (GstBaseTransform * bt, if (direction == GST_PAD_SINK) { newcaps = gst_caps_new_simple ("video/x-raw-rgb", NULL); } else { - newcaps = gst_caps_new_simple ("video/x-raw-gl", NULL); + newcaps = gst_caps_new_simple ("video/x-raw-gl", + "format", G_TYPE_INT, GST_GL_BUFFER_FORMAT_RGBA, + "is_yuv", G_TYPE_BOOLEAN, FALSE, NULL); } newstruct = gst_caps_get_structure (newcaps, 0); gst_structure_set_value (newstruct, "width", width_value); @@ -240,6 +244,8 @@ gst_gl_download_transform_caps (GstBaseTransform * bt, 1, 1, NULL); } + GST_ERROR ("new caps %" GST_PTR_FORMAT, newcaps); + return newcaps; } @@ -258,7 +264,7 @@ gst_gl_download_set_caps (GstBaseTransform * bt, GstCaps * incaps, &download->width, &download->height); if (!ret) { - GST_DEBUG ("bad caps"); + GST_ERROR ("bad caps"); return FALSE; } @@ -271,30 +277,27 @@ gst_gl_download_get_unit_size (GstBaseTransform * trans, GstCaps * caps, { gboolean ret; GstStructure *structure; + int width; + int height; structure = gst_caps_get_structure (caps, 0); if (gst_structure_has_name (structure, "video/x-raw-gl")) { - int width; - int height; + GstGLBufferFormat format; - ret = gst_structure_get_int (structure, "width", &width); - ret &= gst_structure_get_int (structure, "height", &height); - - /* FIXME */ - *size = width * height * 4; + ret = gst_gl_buffer_format_parse_caps (caps, &format, &width, &height); + if (ret) { + *size = gst_gl_buffer_format_get_size (format, width, height); + } } else { - int width; - int height; + GstVideoFormat format; - ret = gst_structure_get_int (structure, "width", &width); - ret &= gst_structure_get_int (structure, "height", &height); - - /* FIXME */ - *size = width * height * 4; + ret = gst_video_format_parse_caps (caps, &format, &width, &height); + if (ret) { + *size = gst_video_format_get_size (format, width, height); + } } - - return TRUE; + return ret; } static GstFlowReturn diff --git a/gst/gl/gstglfilter.c b/gst/gl/gstglfilter.c index 1ff05adf9d..a2175affd6 100644 --- a/gst/gl/gstglfilter.c +++ b/gst/gl/gstglfilter.c @@ -49,21 +49,27 @@ GST_STATIC_PAD_TEMPLATE ("sink", #define DEBUG_INIT(bla) \ GST_DEBUG_CATEGORY_INIT (gst_gl_filter_debug, "glfilter", 0, "glfilter element"); -GST_BOILERPLATE_FULL (GstGLFilter, gst_gl_filter, GstElement, - GST_TYPE_ELEMENT, DEBUG_INIT); +GST_BOILERPLATE_FULL (GstGLFilter, gst_gl_filter, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM, DEBUG_INIT); static void gst_gl_filter_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_gl_filter_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstFlowReturn gst_gl_filter_chain (GstPad * pad, GstBuffer * buf); static void gst_gl_filter_reset (GstGLFilter * filter); -static GstStateChangeReturn -gst_gl_filter_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_gl_filter_sink_setcaps (GstPad * pad, GstCaps * caps); +static gboolean gst_gl_filter_start (GstBaseTransform * bt); +static gboolean gst_gl_filter_stop (GstBaseTransform * bt); +static gboolean gst_gl_filter_get_unit_size (GstBaseTransform * trans, + GstCaps * caps, guint * size); +static GstFlowReturn gst_gl_filter_transform (GstBaseTransform * bt, + GstBuffer * inbuf, GstBuffer * outbuf); +static GstFlowReturn gst_gl_filter_prepare_output_buffer (GstBaseTransform * + trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf); +static gboolean gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, + GstCaps * outcaps); static gboolean gst_gl_filter_do_transform (GstGLFilter * filter, - GstGLBuffer * outbuf, GstGLBuffer * inbuf); + GstGLBuffer * inbuf, GstGLBuffer * outbuf); static void @@ -86,20 +92,23 @@ gst_gl_filter_class_init (GstGLFilterClass * klass) gobject_class->set_property = gst_gl_filter_set_property; gobject_class->get_property = gst_gl_filter_get_property; - GST_ELEMENT_CLASS (klass)->change_state = gst_gl_filter_change_state; + GST_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_filter_transform; + GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_filter_start; + GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_filter_stop; + GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_filter_set_caps; + GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_filter_get_unit_size; + GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer = + gst_gl_filter_prepare_output_buffer; } static void gst_gl_filter_init (GstGLFilter * filter, GstGLFilterClass * klass) { - gst_element_create_all_pads (GST_ELEMENT (filter)); + //gst_element_create_all_pads (GST_ELEMENT (filter)); filter->sinkpad = gst_element_get_static_pad (GST_ELEMENT (filter), "sink"); filter->srcpad = gst_element_get_static_pad (GST_ELEMENT (filter), "src"); - gst_pad_set_setcaps_function (filter->sinkpad, gst_gl_filter_sink_setcaps); - gst_pad_set_chain_function (filter->sinkpad, gst_gl_filter_chain); - gst_gl_filter_reset (filter); } @@ -136,143 +145,108 @@ gst_gl_filter_reset (GstGLFilter * filter) g_object_unref (filter->display); filter->display = NULL; } - filter->format = GST_GL_BUFFER_FORMAT_RGB; + filter->format = GST_GL_BUFFER_FORMAT_UNKNOWN; + filter->width = 0; + filter->height = 0; } static gboolean -gst_gl_filter_start (GstGLFilter * filter) +gst_gl_filter_start (GstBaseTransform * bt) { - GstGLFilterClass *filter_class; - gboolean ret; - - filter_class = GST_GL_FILTER_GET_CLASS (filter); - - filter->format = GST_GL_BUFFER_FORMAT_RGB; - filter->display = gst_gl_display_new (); - ret = gst_gl_display_connect (filter->display, NULL); - if (!ret) - return FALSE; - - if (filter_class->start) { - ret = filter_class->start (filter); - } - - return ret; -} - -static gboolean -gst_gl_filter_stop (GstGLFilter * filter) -{ - GstGLFilterClass *filter_class; - gboolean ret; - - filter_class = GST_GL_FILTER_GET_CLASS (filter); - - gst_gl_filter_reset (filter); - - if (filter_class->stop) { - ret = filter_class->stop (filter); - } - - g_object_unref (filter->display); - filter->display = NULL; return TRUE; } static gboolean -gst_gl_filter_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_gl_filter_stop (GstBaseTransform * bt) +{ + GstGLFilter *filter = GST_GL_FILTER (bt); + + gst_gl_filter_reset (filter); + + return TRUE; +} + +static gboolean +gst_gl_filter_get_unit_size (GstBaseTransform * trans, GstCaps * caps, + guint * size) +{ + gboolean ret; + GstGLBufferFormat format; + int width; + int height; + + ret = gst_gl_buffer_format_parse_caps (caps, &format, &width, &height); + if (ret) { + *size = gst_gl_buffer_format_get_size (format, width, height); + } + + return TRUE; +} + +static GstFlowReturn +gst_gl_filter_prepare_output_buffer (GstBaseTransform * trans, + GstBuffer * inbuf, gint size, GstCaps * caps, GstBuffer ** buf) +{ + GstGLFilter *filter; + GstGLBuffer *gl_inbuf = GST_GL_BUFFER (inbuf); + GstGLBuffer *gl_outbuf; + + filter = GST_GL_FILTER (trans); + + if (filter->display == NULL) { + filter->display = gl_inbuf->display; + } + + gl_outbuf = gst_gl_buffer_new_with_format (filter->display, + filter->format, filter->width, filter->height); + + *buf = GST_BUFFER (gl_outbuf); + gst_buffer_set_caps (*buf, caps); + + return GST_FLOW_OK; +} + +static gboolean +gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, + GstCaps * outcaps) { GstGLFilter *filter; gboolean ret; - GstStructure *structure; - filter = GST_GL_FILTER (gst_pad_get_parent (pad)); + filter = GST_GL_FILTER (bt); - structure = gst_caps_get_structure (caps, 0); + ret = gst_gl_buffer_format_parse_caps (incaps, &filter->format, + &filter->width, &filter->height); - ret = gst_structure_get_int (structure, "width", &filter->width); - ret &= gst_structure_get_int (structure, "height", &filter->height); - if (!ret) + if (!ret) { + GST_DEBUG ("bad caps"); return FALSE; + } - GST_DEBUG ("setcaps %d %d", filter->width, filter->height); - - ret = gst_pad_set_caps (filter->srcpad, caps); + GST_ERROR ("set_caps %d %d", filter->width, filter->height); return ret; } static GstFlowReturn -gst_gl_filter_chain (GstPad * pad, GstBuffer * buf) +gst_gl_filter_transform (GstBaseTransform * bt, GstBuffer * inbuf, + GstBuffer * outbuf) { GstGLFilter *filter; - GstGLBuffer *inbuf; - GstGLBuffer *outbuf; + GstGLBuffer *gl_inbuf = GST_GL_BUFFER (inbuf); + GstGLBuffer *gl_outbuf = GST_GL_BUFFER (outbuf); - filter = GST_GL_FILTER (gst_pad_get_parent (pad)); - inbuf = GST_GL_BUFFER (buf); + filter = GST_GL_FILTER (bt); - outbuf = gst_gl_buffer_new (inbuf->display, filter->format, - filter->width, filter->height); + gst_gl_filter_do_transform (filter, gl_inbuf, gl_outbuf); - gst_buffer_copy_metadata (GST_BUFFER (outbuf), buf, - GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS); - gst_buffer_set_caps (GST_BUFFER (outbuf), GST_PAD_CAPS (filter->srcpad)); - - gst_gl_filter_do_transform (filter, outbuf, inbuf); - - gst_pad_push (filter->srcpad, GST_BUFFER (outbuf)); - - gst_buffer_unref (buf); - gst_object_unref (filter); return GST_FLOW_OK; } -static GstStateChangeReturn -gst_gl_filter_change_state (GstElement * element, GstStateChange transition) -{ - GstGLFilter *filter; - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - - GST_DEBUG ("change state"); - - filter = GST_GL_FILTER (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_gl_filter_start (filter); - 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: - gst_gl_filter_stop (filter); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - static gboolean gst_gl_filter_do_transform (GstGLFilter * filter, - GstGLBuffer * outbuf, GstGLBuffer * inbuf) + GstGLBuffer * inbuf, GstGLBuffer * outbuf) { GstGLDisplay *display = inbuf->display; GstGLFilterClass *filter_class; @@ -311,9 +285,10 @@ gst_gl_filter_do_transform (GstGLFilter * filter, glColor4f (1, 1, 1, 1); glEnable (GL_TEXTURE_RECTANGLE_ARB); + glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, inbuf->texture); - filter_class->transform (filter, outbuf, inbuf); + filter_class->filter (filter, inbuf, outbuf); #if 0 glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); diff --git a/gst/gl/gstglfilter.h b/gst/gl/gstglfilter.h index 01b915f544..513d6e9b90 100644 --- a/gst/gl/gstglfilter.h +++ b/gst/gl/gstglfilter.h @@ -23,6 +23,7 @@ #include #include +#include #include #define GST_TYPE_GL_FILTER (gst_gl_filter_get_type()) @@ -35,13 +36,11 @@ typedef struct _GstGLFilter GstGLFilter; typedef struct _GstGLFilterClass GstGLFilterClass; typedef gboolean (*GstGLFilterProcessFunc) (GstGLFilter *filter, - GstGLBuffer *outbuf, GstGLBuffer *inbuf); -typedef gboolean (*GstGLFilterStartFunc) (GstGLFilter *filter); -typedef gboolean (*GstGLFilterStopFunc) (GstGLFilter *filter); + GstGLBuffer *inbuf, GstGLBuffer *outbuf); struct _GstGLFilter { - GstElement element; + GstBaseTransform base_transform; GstPad *srcpad; GstPad *sinkpad; @@ -56,10 +55,8 @@ struct _GstGLFilter struct _GstGLFilterClass { - GstElementClass element_class; - GstGLFilterProcessFunc transform; - GstGLFilterStartFunc start; - GstGLFilterStopFunc stop; + GstBaseTransformClass base_transform_class; + GstGLFilterProcessFunc filter; }; GType gst_gl_filter_get_type(void); diff --git a/gst/gl/gstglfilterexample.c b/gst/gl/gstglfilterexample.c index aa709abcfa..8f7de08f96 100644 --- a/gst/gl/gstglfilterexample.c +++ b/gst/gl/gstglfilterexample.c @@ -59,24 +59,6 @@ static const GstElementDetails element_details = GST_ELEMENT_DETAILS ("FIXME", "FIXME example filter", "FIXME "); -#if 0 -#define GST_GL_VIDEO_CAPS "video/x-raw-gl" - -static GstStaticPadTemplate gst_gl_filter_example_src_pad_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_GL_VIDEO_CAPS) - ); - -static GstStaticPadTemplate gst_gl_filter_example_sink_pad_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_GL_VIDEO_CAPS) - ); -#endif - enum { PROP_0 @@ -93,11 +75,8 @@ static void gst_gl_filter_example_set_property (GObject * object, guint prop_id, static void gst_gl_filter_example_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_gl_filter_example_reset (GstGLFilterExample * filter); -static gboolean gst_gl_filter_example_transform (GstGLFilter * filter, - GstGLBuffer * outbuf, GstGLBuffer * inbuf); -static gboolean gst_gl_filter_example_start (GstGLFilter * filter); -static gboolean gst_gl_filter_example_stop (GstGLFilter * filter); +static gboolean gst_gl_filter_example_filter (GstGLFilter * filter, + GstGLBuffer * inbuf, GstGLBuffer * outbuf); static void @@ -106,13 +85,6 @@ gst_gl_filter_example_base_init (gpointer klass) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_set_details (element_class, &element_details); - -#if 0 - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_gl_filter_example_src_pad_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_gl_filter_example_sink_pad_template)); -#endif } static void @@ -124,16 +96,13 @@ gst_gl_filter_example_class_init (GstGLFilterExampleClass * klass) gobject_class->set_property = gst_gl_filter_example_set_property; gobject_class->get_property = gst_gl_filter_example_get_property; - GST_GL_FILTER_CLASS (klass)->transform = gst_gl_filter_example_transform; - GST_GL_FILTER_CLASS (klass)->start = gst_gl_filter_example_start; - GST_GL_FILTER_CLASS (klass)->stop = gst_gl_filter_example_stop; + GST_GL_FILTER_CLASS (klass)->filter = gst_gl_filter_example_filter; } static void gst_gl_filter_example_init (GstGLFilterExample * filter, GstGLFilterExampleClass * klass) { - gst_gl_filter_example_reset (filter); } static void @@ -162,32 +131,9 @@ gst_gl_filter_example_get_property (GObject * object, guint prop_id, } } -static void -gst_gl_filter_example_reset (GstGLFilterExample * filter) -{ - -} - static gboolean -gst_gl_filter_example_start (GstGLFilter * _filter) -{ - //GstGLFilterExample *filter = GST_GL_FILTER_EXAMPLE(_filter); - - return TRUE; -} - -static gboolean -gst_gl_filter_example_stop (GstGLFilter * _filter) -{ - GstGLFilterExample *filter = GST_GL_FILTER_EXAMPLE (_filter); - - gst_gl_filter_example_reset (filter); - return TRUE; -} - -static gboolean -gst_gl_filter_example_transform (GstGLFilter * filter, GstGLBuffer * outbuf, - GstGLBuffer * inbuf) +gst_gl_filter_example_filter (GstGLFilter * filter, GstGLBuffer * inbuf, + GstGLBuffer * outbuf) { //GstGLFilterExample *example = GST_GL_FILTER_EXAMPLE(filter); int i, j; diff --git a/gst/gl/gstgltestsrc.c b/gst/gl/gstgltestsrc.c index 563f3c5f13..0a9149b4ff 100644 --- a/gst/gl/gstgltestsrc.c +++ b/gst/gl/gstgltestsrc.c @@ -520,8 +520,7 @@ gst_gl_test_src_create (GstPushSrc * psrc, GstBuffer ** buffer) GST_LOG_OBJECT (src, "creating buffer %dx%d image for frame %d", src->width, src->height, (gint) src->n_frames); - outbuf = gst_gl_buffer_new (src->display, GST_GL_BUFFER_FORMAT_RGB, - src->width, src->height); + outbuf = gst_gl_buffer_new (src->display, src->width, src->height); gst_buffer_set_caps (GST_BUFFER (outbuf), GST_PAD_CAPS (GST_BASE_SRC_PAD (psrc))); @@ -540,6 +539,7 @@ gst_gl_test_src_create (GstPushSrc * psrc, GstBuffer ** buffer) GL_FRAMEBUFFER_COMPLETE_EXT); glViewport (0, 0, outbuf->width, outbuf->height); + gst_gl_display_check_error (outbuf->display, __LINE__); #if 0 glClearColor (0.3, 0.3, 0.3, 1.0); @@ -556,8 +556,10 @@ gst_gl_test_src_create (GstPushSrc * psrc, GstBuffer ** buffer) } glFlush (); + gst_gl_display_check_error (outbuf->display, __LINE__); glDeleteFramebuffersEXT (1, &fbo); + gst_gl_display_check_error (outbuf->display, __LINE__); gst_gl_display_unlock (outbuf->display); diff --git a/gst/gl/gstglupload.c b/gst/gl/gstglupload.c index 2405d61f1f..036fe55fd8 100644 --- a/gst/gl/gstglupload.c +++ b/gst/gl/gstglupload.c @@ -23,6 +23,7 @@ #endif #include +#include #include #include @@ -42,7 +43,7 @@ typedef void (*GstGLUploadProcessFunc) (GstGLUpload *, guint8 *, guint); struct _GstGLUpload { - GstElement element; + GstBaseTransform base_transform; GstPad *srcpad; GstPad *sinkpad; @@ -60,7 +61,7 @@ struct _GstGLUpload struct _GstGLUploadClass { - GstElementClass element_class; + GstBaseTransformClass base_transform_class; }; static const GstElementDetails element_details = GST_ELEMENT_DETAILS ("FIXME", @@ -94,19 +95,29 @@ enum #define DEBUG_INIT(bla) \ GST_DEBUG_CATEGORY_INIT (gst_gl_upload_debug, "glupload", 0, "glupload element"); -GST_BOILERPLATE_FULL (GstGLUpload, gst_gl_upload, GstElement, - GST_TYPE_ELEMENT, DEBUG_INIT); +GST_BOILERPLATE_FULL (GstGLUpload, gst_gl_upload, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM, DEBUG_INIT); static void gst_gl_upload_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_gl_upload_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstFlowReturn gst_gl_upload_chain (GstPad * pad, GstBuffer * buf); static void gst_gl_upload_reset (GstGLUpload * upload); -static GstStateChangeReturn -gst_gl_upload_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_gl_upload_sink_setcaps (GstPad * pad, GstCaps * caps); + +static void gst_gl_upload_reset (GstGLUpload * upload); +static gboolean gst_gl_upload_set_caps (GstBaseTransform * bt, + GstCaps * incaps, GstCaps * outcaps); +static GstCaps *gst_gl_upload_transform_caps (GstBaseTransform * bt, + GstPadDirection direction, GstCaps * caps); +static gboolean gst_gl_upload_start (GstBaseTransform * bt); +static gboolean gst_gl_upload_stop (GstBaseTransform * bt); +static GstFlowReturn gst_gl_upload_prepare_output_buffer (GstBaseTransform * + trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf); +static GstFlowReturn gst_gl_upload_transform (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer * outbuf); +static gboolean gst_gl_upload_get_unit_size (GstBaseTransform * trans, + GstCaps * caps, guint * size); static void @@ -131,19 +142,20 @@ gst_gl_upload_class_init (GstGLUploadClass * klass) gobject_class->set_property = gst_gl_upload_set_property; gobject_class->get_property = gst_gl_upload_get_property; - GST_ELEMENT_CLASS (klass)->change_state = gst_gl_upload_change_state; + GST_BASE_TRANSFORM_CLASS (klass)->transform_caps = + gst_gl_upload_transform_caps; + GST_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_upload_transform; + GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_upload_start; + GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_upload_stop; + GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_upload_set_caps; + GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_upload_get_unit_size; + GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer = + gst_gl_upload_prepare_output_buffer; } static void gst_gl_upload_init (GstGLUpload * upload, GstGLUploadClass * klass) { - gst_element_create_all_pads (GST_ELEMENT (upload)); - - upload->sinkpad = gst_element_get_static_pad (GST_ELEMENT (upload), "sink"); - upload->srcpad = gst_element_get_static_pad (GST_ELEMENT (upload), "src"); - - gst_pad_set_setcaps_function (upload->sinkpad, gst_gl_upload_sink_setcaps); - gst_pad_set_chain_function (upload->sinkpad, gst_gl_upload_chain); gst_gl_upload_reset (upload); } @@ -186,25 +198,30 @@ gst_gl_upload_reset (GstGLUpload * upload) } static gboolean -gst_gl_upload_start (GstGLUpload * upload) +gst_gl_upload_start (GstBaseTransform * bt) { + GstGLUpload *upload = GST_GL_UPLOAD (bt); gboolean ret; upload->format = GST_GL_BUFFER_FORMAT_RGB; upload->display = gst_gl_display_new (); ret = gst_gl_display_connect (upload->display, NULL); + //upload->format = GST_VIDEO_FORMAT_RGBx; - return ret; + return TRUE; } static gboolean -gst_gl_upload_stop (GstGLUpload * upload) +gst_gl_upload_stop (GstBaseTransform * bt) { + GstGLUpload *upload = GST_GL_UPLOAD (bt); + gst_gl_upload_reset (upload); return TRUE; } +#if 0 static gboolean gst_gl_upload_sink_setcaps (GstPad * pad, GstCaps * caps) { @@ -246,7 +263,9 @@ gst_gl_upload_sink_setcaps (GstPad * pad, GstCaps * caps) return ret; } +#endif +#if 0 static GstFlowReturn gst_gl_upload_chain (GstPad * pad, GstBuffer * buf) { @@ -277,44 +296,142 @@ gst_gl_upload_chain (GstPad * pad, GstBuffer * buf) gst_object_unref (upload); return GST_FLOW_OK; } +#endif -static GstStateChangeReturn -gst_gl_upload_change_state (GstElement * element, GstStateChange transition) +static GstCaps * +gst_gl_upload_transform_caps (GstBaseTransform * bt, + GstPadDirection direction, GstCaps * caps) { GstGLUpload *upload; - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstStructure *structure; + GstCaps *newcaps; + GstStructure *newstruct; + const GValue *width_value; + const GValue *height_value; + const GValue *framerate_value; + const GValue *par_value; - GST_DEBUG ("change state"); + upload = GST_GL_UPLOAD (bt); - upload = GST_GL_UPLOAD (element); + GST_ERROR ("transform caps %" GST_PTR_FORMAT, caps); - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_gl_upload_start (upload); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; + 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) { + newcaps = gst_caps_new_simple ("video/x-raw-rgb", NULL); + } else { + newcaps = gst_caps_new_simple ("video/x-raw-gl", + "format", G_TYPE_INT, GST_GL_BUFFER_FORMAT_RGBA, + "is_yuv", G_TYPE_BOOLEAN, FALSE, 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); } - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; + GST_ERROR ("new caps %" GST_PTR_FORMAT, newcaps); - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_gl_upload_stop (upload); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; + return newcaps; +} + +static gboolean +gst_gl_upload_set_caps (GstBaseTransform * bt, GstCaps * incaps, + GstCaps * outcaps) +{ + GstGLUpload *upload; + gboolean ret; + + upload = GST_GL_UPLOAD (bt); + + GST_DEBUG ("called with %" GST_PTR_FORMAT, incaps); + + ret = gst_video_format_parse_caps (incaps, &upload->video_format, + &upload->width, &upload->height); + + if (!ret) { + GST_DEBUG ("bad caps"); + return FALSE; } return ret; } + +static gboolean +gst_gl_upload_get_unit_size (GstBaseTransform * trans, GstCaps * caps, + guint * size) +{ + gboolean ret; + GstStructure *structure; + int width; + int height; + + structure = gst_caps_get_structure (caps, 0); + if (gst_structure_has_name (structure, "video/x-raw-gl")) { + GstGLBufferFormat format; + + ret = gst_gl_buffer_format_parse_caps (caps, &format, &width, &height); + if (ret) { + *size = gst_gl_buffer_format_get_size (format, width, height); + } + } else { + GstVideoFormat format; + + ret = gst_video_format_parse_caps (caps, &format, &width, &height); + if (ret) { + *size = gst_video_format_get_size (format, width, height); + } + } + + return TRUE; +} + +static GstFlowReturn +gst_gl_upload_prepare_output_buffer (GstBaseTransform * trans, + GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf) +{ + GstGLUpload *upload; + GstGLBuffer *gl_outbuf; + + upload = GST_GL_UPLOAD (trans); + + gl_outbuf = gst_gl_buffer_new_from_video_format (upload->display, + upload->video_format, upload->width, upload->height); + + *buf = GST_BUFFER (gl_outbuf); + gst_buffer_set_caps (*buf, caps); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_gl_upload_transform (GstBaseTransform * trans, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + GstGLUpload *upload; + GstGLBuffer *gl_outbuf = GST_GL_BUFFER (outbuf); + + upload = GST_GL_UPLOAD (trans); + + GST_DEBUG ("uploading %p size %d", + GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf)); + gst_gl_buffer_upload (gl_outbuf, upload->video_format, + GST_BUFFER_DATA (inbuf)); + + if (upload->peek) { + gst_gl_display_draw_texture (gl_outbuf->display, gl_outbuf->texture, + gl_outbuf->width, gl_outbuf->height); + } + + return GST_FLOW_OK; +}