eagl: fix handling of surface dimension changes

Detect when the eagl surface changed its dimension (when the user rotates
the device for example) and adapt the egl internals to draw to that,
preventing that ios resizes the image again when drawing.

This is particularly harmful when eagl would scale down a image
to draw and the ios screen would scale it back up because the
surface is now bigger than when the element was configured.
This commit is contained in:
Thiago Santos 2013-05-15 11:49:22 -03:00
parent 27d726fbfa
commit ef66e39d03
2 changed files with 49 additions and 20 deletions

View File

@ -56,11 +56,15 @@ struct _GstEaglContext
EAGLContext *eagl_context; EAGLContext *eagl_context;
GLuint framebuffer; GLuint framebuffer;
GLuint color_renderbuffer; GLuint color_renderbuffer;
GLuint depth_renderbuffer;
UIView *window; UIView *window;
UIView *used_window; UIView *used_window;
}; };
static gboolean
gst_egl_adaptation_update_surface (GstEglAdaptationContext * ctx);
void void
gst_egl_adaptation_init (GstEglAdaptationContext * ctx) gst_egl_adaptation_init (GstEglAdaptationContext * ctx)
{ {
@ -179,8 +183,13 @@ gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx)
__block CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[ctx->eaglctx->window layer]; __block CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_sync(dispatch_get_main_queue(), ^{
/* Allocate framebuffer */
glGenFramebuffers(1, &framebuffer); if (ctx->eaglctx->framebuffer) {
framebuffer = ctx->eaglctx->framebuffer;
} else {
/* Allocate framebuffer */
glGenFramebuffers(1, &framebuffer);
}
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
/* Allocate color render buffer */ /* Allocate color render buffer */
@ -212,6 +221,9 @@ gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx)
ctx->eaglctx->framebuffer = framebuffer; ctx->eaglctx->framebuffer = framebuffer;
ctx->eaglctx->color_renderbuffer = colorRenderbuffer; ctx->eaglctx->color_renderbuffer = colorRenderbuffer;
ctx->eaglctx->depth_renderbuffer = colorRenderbuffer;
ctx->surface_width = width;
ctx->surface_height = height;
glBindRenderbuffer(GL_RENDERBUFFER, ctx->eaglctx->color_renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, ctx->eaglctx->color_renderbuffer);
return TRUE; return TRUE;
@ -260,18 +272,18 @@ gboolean
gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext * gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext *
ctx) ctx)
{ {
GLint width; CAEAGLLayer *layer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
GLint height; CGSize size = layer.frame.size;
/* Get renderbuffer width/height */ if (size.width != ctx->surface_width || size.height != ctx->surface_height) {
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width); ctx->surface_width = size.width;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height); ctx->surface_height = size.height;
GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels",
if (width != ctx->surface_width || height != ctx->surface_height) { (gint) size.width, (gint) size.height);
ctx->surface_width = width; if (!gst_egl_adaptation_update_surface (ctx)) {
ctx->surface_height = height; GST_WARNING_OBJECT (ctx->element, "Failed to update surface "
GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels", width, "to new dimensions");
height); }
return TRUE; return TRUE;
} }
@ -302,6 +314,23 @@ gst_egl_adaptation_destroy_surface (GstEglAdaptationContext * ctx)
} }
} }
static gboolean
gst_egl_adaptation_update_surface (GstEglAdaptationContext * ctx)
{
glBindFramebuffer(GL_FRAMEBUFFER, ctx->eaglctx->framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &ctx->eaglctx->depth_renderbuffer);
glBindRenderbuffer (GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &ctx->eaglctx->color_renderbuffer);
return gst_egl_adaptation_create_surface (ctx);
}
void void
gst_egl_adaptation_destroy_context (GstEglAdaptationContext * ctx) gst_egl_adaptation_destroy_context (GstEglAdaptationContext * ctx)
{ {

View File

@ -204,8 +204,7 @@ static void gst_eglglessink_set_render_rectangle (GstVideoOverlay * overlay,
/* Utility */ /* Utility */
static gboolean gst_eglglessink_create_window (GstEglGlesSink * static gboolean gst_eglglessink_create_window (GstEglGlesSink *
eglglessink, gint width, gint height); eglglessink, gint width, gint height);
static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink);
gboolean reset);
static gboolean static gboolean
gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps); gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps);
static GstFlowReturn gst_eglglessink_upload (GstEglGlesSink * sink, static GstFlowReturn gst_eglglessink_upload (GstEglGlesSink * sink,
@ -740,17 +739,17 @@ gst_eglglessink_expose (GstVideoOverlay * overlay)
} }
static gboolean static gboolean
gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset) gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink)
{ {
gdouble render_width, render_height; gdouble render_width, render_height;
gdouble texture_width, texture_height; gdouble texture_width, texture_height;
gdouble x1, x2, y1, y2; gdouble x1, x2, y1, y2;
gdouble tx1, tx2, ty1, ty2; gdouble tx1, tx2, ty1, ty2;
GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d, should reset %d", GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d",
eglglessink->egl_context->have_vbo, reset); eglglessink->egl_context->have_vbo);
if (eglglessink->egl_context->have_vbo && reset) { if (eglglessink->egl_context->have_vbo) {
glDeleteBuffers (1, &eglglessink->egl_context->position_buffer); glDeleteBuffers (1, &eglglessink->egl_context->position_buffer);
glDeleteBuffers (1, &eglglessink->egl_context->index_buffer); glDeleteBuffers (1, &eglglessink->egl_context->index_buffer);
eglglessink->egl_context->have_vbo = FALSE; eglglessink->egl_context->have_vbo = FALSE;
@ -929,6 +928,7 @@ gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
goto HANDLE_ERROR_LOCKED; goto HANDLE_ERROR_LOCKED;
eglglessink->egl_context->have_vbo = TRUE; eglglessink->egl_context->have_vbo = TRUE;
GST_DEBUG_OBJECT (eglglessink, "VBO setup done"); GST_DEBUG_OBJECT (eglglessink, "VBO setup done");
return TRUE; return TRUE;
@ -1673,7 +1673,7 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink)
glClear (GL_COLOR_BUFFER_BIT); glClear (GL_COLOR_BUFFER_BIT);
} }
if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) { if (!gst_eglglessink_setup_vbo (eglglessink)) {
GST_OBJECT_UNLOCK (eglglessink); GST_OBJECT_UNLOCK (eglglessink);
GST_ERROR_OBJECT (eglglessink, "VBO setup failed"); GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
goto HANDLE_ERROR; goto HANDLE_ERROR;