eglglessink: Fix handling of GstVideoOverlay::set_render_rect() and crop metadata
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 26 Dec 2012 13:39:03 +0000 (14:39 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 26 Dec 2012 13:39:03 +0000 (14:39 +0100)
ext/eglgles/gsteglglessink.c
ext/eglgles/gsteglglessink.h
ext/eglgles/video_platform_wrapper.c

index 1a63f65c0c50b68c4ba6dc096dc698b8d2000eef..1dc7ae58d3f44c04776f1b9a590cdd23d99da835 100644 (file)
@@ -404,8 +404,6 @@ static inline gboolean egl_init (GstEglGlesSink * eglglessink);
 static gboolean gst_eglglessink_context_make_current (GstEglGlesSink *
     eglglessink, gboolean bind);
 static void gst_eglglessink_wipe_eglglesctx (GstEglGlesSink * eglglessink);
-static inline void gst_eglglessink_reset_display_region (GstEglGlesSink *
-    eglglessink);
 
 #define parent_class gst_eglglessink_parent_class
 G_DEFINE_TYPE_WITH_CODE (GstEglGlesSink, gst_eglglessink, GST_TYPE_VIDEO_SINK,
@@ -727,21 +725,6 @@ gst_eglglessink_wipe_eglglesctx (GstEglGlesSink * eglglessink)
         eglglessink->eglglesctx.eglcontext);
     eglglessink->eglglesctx.eglcontext = NULL;
   }
-
-  gst_eglglessink_reset_display_region (eglglessink);
-}
-
-/* Reset display region
- * XXX: Should probably keep old ones if set_render_rect()
- * has been called.
- */
-static inline void
-gst_eglglessink_reset_display_region (GstEglGlesSink * eglglessink)
-{
-  GST_OBJECT_LOCK (eglglessink);
-  eglglessink->display_region.w = 0;
-  eglglessink->display_region.h = 0;
-  GST_OBJECT_UNLOCK (eglglessink);
 }
 
 static gboolean
@@ -766,8 +749,10 @@ gst_eglglessink_start (GstEglGlesSink * eglglessink)
     goto HANDLE_ERROR;
   }
 
-  gst_eglglessink_reset_display_region (eglglessink);
   eglglessink->last_flow = GST_FLOW_OK;
+  eglglessink->display_region.w = 0;
+  eglglessink->display_region.h = 0;
+
   gst_data_queue_set_flushing (eglglessink->queue, FALSE);
 
 #if !GLIB_CHECK_VERSION (2, 31, 0)
@@ -916,7 +901,8 @@ gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink)
 static gboolean
 gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
 {
-  gdouble surface_width, surface_height;
+  gdouble render_width, render_height;
+  gdouble texture_width, texture_height;
   gdouble x1, x2, y1, y2;
   gdouble tx1, tx2, ty1, ty2;
 
@@ -929,26 +915,25 @@ gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
     eglglessink->have_vbo = FALSE;
   }
 
-  surface_width = eglglessink->eglglesctx.surface_width;
-  surface_height = eglglessink->eglglesctx.surface_height;
+  render_width = eglglessink->render_region.w;
+  render_height = eglglessink->render_region.h;
+
+  texture_width = eglglessink->configured_info.width;
+  texture_height = eglglessink->configured_info.height;
 
   GST_DEBUG_OBJECT (eglglessink, "Performing VBO setup");
 
-  x1 = (eglglessink->display_region.x / surface_width) * 2.0 - 1;
-  y1 = (eglglessink->display_region.y / surface_height) * 2.0 - 1;
+  x1 = (eglglessink->display_region.x / render_width) * 2.0 - 1;
+  y1 = (eglglessink->display_region.y / render_height) * 2.0 - 1;
   x2 = ((eglglessink->display_region.x +
-          eglglessink->display_region.w) / surface_width) * 2.0 - 1;
+          eglglessink->display_region.w) / render_width) * 2.0 - 1;
   y2 = ((eglglessink->display_region.y +
-          eglglessink->display_region.h) / surface_height) * 2.0 - 1;
+          eglglessink->display_region.h) / render_height) * 2.0 - 1;
 
-  tx1 = (eglglessink->crop.x / eglglessink->configured_info.width);
-  tx2 =
-      ((eglglessink->crop.x +
-          eglglessink->crop.width) / eglglessink->configured_info.width);
-  ty1 = (eglglessink->crop.y / eglglessink->configured_info.height);
-  ty2 =
-      ((eglglessink->crop.y +
-          eglglessink->crop.height) / eglglessink->configured_info.height);
+  tx1 = (eglglessink->crop.x / texture_width);
+  tx2 = ((eglglessink->crop.x + eglglessink->crop.w) / texture_width);
+  ty1 = (eglglessink->crop.y / texture_height);
+  ty2 = ((eglglessink->crop.y + eglglessink->crop.h) / texture_height);
 
   eglglessink->eglglesctx.position_array[0].x = x2;
   eglglessink->eglglesctx.position_array[0].y = y2;
@@ -1676,19 +1661,13 @@ gst_eglglessink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y,
   g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
 
   GST_OBJECT_LOCK (eglglessink);
-  if (width == -1 && height == -1) {
-    /* This is the set-defaults condition according to
-     * the xOverlay interface docs
-     */
-    gst_eglglessink_reset_display_region (eglglessink);
-  } else {
-    GST_OBJECT_LOCK (eglglessink);
-    eglglessink->display_region.x = x;
-    eglglessink->display_region.y = y;
-    eglglessink->display_region.w = width;
-    eglglessink->display_region.h = height;
-    GST_OBJECT_UNLOCK (eglglessink);
-  }
+  eglglessink->render_region.x = x;
+  eglglessink->render_region.y = y;
+  eglglessink->render_region.w = width;
+  eglglessink->render_region.h = height;
+  eglglessink->render_region_changed = TRUE;
+  eglglessink->render_region_user = (width != -1 && height != -1);
+  GST_OBJECT_UNLOCK (eglglessink);
 
   return;
 }
@@ -1745,13 +1724,13 @@ gst_eglglessink_crop_changed (GstEglGlesSink * eglglessink,
   if (crop) {
     return (crop->x != eglglessink->crop.x ||
         crop->y != eglglessink->crop.y ||
-        crop->width != eglglessink->crop.width ||
-        crop->height != eglglessink->crop.height);
+        crop->width != eglglessink->crop.w ||
+        crop->height != eglglessink->crop.h);
   }
 
   return (eglglessink->crop.x != 0 || eglglessink->crop.y != 0 ||
-      eglglessink->crop.width != GST_VIDEO_SINK_WIDTH (eglglessink) ||
-      eglglessink->crop.height != GST_VIDEO_SINK_HEIGHT (eglglessink));
+      eglglessink->crop.w != eglglessink->configured_info.width ||
+      eglglessink->crop.h != eglglessink->configured_info.height);
 }
 
 /* Rendering and display */
@@ -1760,16 +1739,12 @@ gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
     GstBuffer * buf)
 {
   GstVideoFrame vframe;
-  GstVideoRectangle frame, surface;
   gint w, h;
   guint dar_n, dar_d;
   GstVideoCropMeta *crop = NULL;
 
   memset (&vframe, 0, sizeof (vframe));
 
-  w = GST_VIDEO_SINK_WIDTH (eglglessink);
-  h = GST_VIDEO_SINK_HEIGHT (eglglessink);
-
   if (buf) {
     crop = gst_buffer_get_video_crop_meta (buf);
 
@@ -1780,6 +1755,9 @@ gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
     }
   }
 
+  w = GST_VIDEO_FRAME_WIDTH (&vframe);
+  h = GST_VIDEO_FRAME_HEIGHT (&vframe);
+
   GST_DEBUG_OBJECT (eglglessink,
       "Got good buffer %p. Sink geometry is %dx%d size %d", buf, w, h,
       buf ? gst_buffer_get_size (buf) : -1);
@@ -1901,72 +1879,84 @@ gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
    * force_aspect_ratio to FALSE.
    */
   if (gst_eglglessink_update_surface_dimensions (eglglessink) ||
+      eglglessink->render_region_changed ||
       !eglglessink->display_region.w || !eglglessink->display_region.h ||
       gst_eglglessink_crop_changed (eglglessink, crop)) {
     GST_OBJECT_LOCK (eglglessink);
+
+    if (!eglglessink->render_region_user) {
+      eglglessink->render_region.x = 0;
+      eglglessink->render_region.y = 0;
+      eglglessink->render_region.w = eglglessink->eglglesctx.surface_width;
+      eglglessink->render_region.h = eglglessink->eglglesctx.surface_height;
+    }
+    eglglessink->render_region_changed = FALSE;
+
     if (crop) {
       eglglessink->crop.x = crop->x;
       eglglessink->crop.y = crop->y;
-      eglglessink->crop.width = crop->width;
-      eglglessink->crop.height = crop->height;
+      eglglessink->crop.w = crop->width;
+      eglglessink->crop.h = crop->height;
     } else {
       eglglessink->crop.x = 0;
       eglglessink->crop.y = 0;
-      eglglessink->crop.width = w;
-      eglglessink->crop.height = h;
+      eglglessink->crop.w = w;
+      eglglessink->crop.h = h;
     }
 
     if (!eglglessink->force_aspect_ratio) {
       eglglessink->display_region.x = 0;
       eglglessink->display_region.y = 0;
-      eglglessink->display_region.w = eglglessink->eglglesctx.surface_width;
-      eglglessink->display_region.h = eglglessink->eglglesctx.surface_height;
+      eglglessink->display_region.w = eglglessink->render_region.w;
+      eglglessink->display_region.h = eglglessink->render_region.h;
     } else {
+      GstVideoRectangle frame;
+
+      frame.x = 0;
+      frame.y = 0;
+
       if (!gst_video_calculate_display_ratio (&dar_n, &dar_d,
-              eglglessink->crop.width, eglglessink->crop.height,
+              eglglessink->crop.w, eglglessink->crop.h,
               eglglessink->configured_info.par_n,
               eglglessink->configured_info.par_d,
               eglglessink->eglglesctx.pixel_aspect_ratio,
               EGL_DISPLAY_SCALING)) {
         GST_WARNING_OBJECT (eglglessink, "Could not compute resulting DAR");
-        frame.w = eglglessink->crop.width;
-        frame.h = eglglessink->crop.height;
+        frame.w = eglglessink->crop.w;
+        frame.h = eglglessink->crop.h;
       } else {
         /* Find suitable matching new size acording to dar & par
          * rationale for prefering leaving the height untouched
          * comes from interlacing considerations.
          * XXX: Move this to gstutils?
          */
-        if (eglglessink->crop.height % dar_d == 0) {
+        if (eglglessink->crop.h % dar_d == 0) {
           frame.w =
-              gst_util_uint64_scale_int (eglglessink->crop.height, dar_n,
-              dar_d);
-          frame.h = eglglessink->crop.height;
-        } else if (eglglessink->crop.width % dar_n == 0) {
+              gst_util_uint64_scale_int (eglglessink->crop.h, dar_n, dar_d);
+          frame.h = eglglessink->crop.h;
+        } else if (eglglessink->crop.w % dar_n == 0) {
           frame.h =
-              gst_util_uint64_scale_int (eglglessink->crop.width, dar_d, dar_n);
-          frame.w = eglglessink->crop.width;
+              gst_util_uint64_scale_int (eglglessink->crop.w, dar_d, dar_n);
+          frame.w = eglglessink->crop.w;
         } else {
           /* Neither width nor height can be precisely scaled.
            * Prefer to leave height untouched. See comment above.
            */
           frame.w =
-              gst_util_uint64_scale_int (eglglessink->crop.height, dar_n,
-              dar_d);
-          frame.h = eglglessink->crop.height;
+              gst_util_uint64_scale_int (eglglessink->crop.h, dar_n, dar_d);
+          frame.h = eglglessink->crop.h;
         }
       }
 
-      surface.w = eglglessink->eglglesctx.surface_width;
-      surface.h = eglglessink->eglglesctx.surface_height;
-      gst_video_sink_center_rect (frame, surface,
+      gst_video_sink_center_rect (frame, eglglessink->render_region,
           &eglglessink->display_region, TRUE);
     }
-    GST_OBJECT_UNLOCK (eglglessink);
 
-    glViewport (0, 0,
-        eglglessink->eglglesctx.surface_width,
-        eglglessink->eglglesctx.surface_height);
+    glViewport (eglglessink->render_region.x,
+        eglglessink->eglglesctx.surface_height -
+        eglglessink->render_region.y -
+        eglglessink->render_region.w,
+        eglglessink->render_region.w, eglglessink->render_region.h);
 
     /* Clear the surface once if its content is preserved */
     if (eglglessink->eglglesctx.buffer_preserved) {
@@ -1975,9 +1965,11 @@ gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
     }
 
     if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) {
+      GST_OBJECT_UNLOCK (eglglessink);
       GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
       goto HANDLE_ERROR;
     }
+    GST_OBJECT_UNLOCK (eglglessink);
   }
 
   if (!eglglessink->eglglesctx.buffer_preserved) {
@@ -2440,6 +2432,16 @@ gst_eglglessink_init (GstEglGlesSink * eglglessink)
   eglglessink->queue =
       gst_data_queue_new (queue_check_full_func, NULL, NULL, NULL);
   eglglessink->last_flow = GST_FLOW_FLUSHING;
+
+  eglglessink->render_region.x = 0;
+  eglglessink->render_region.y = 0;
+  eglglessink->render_region.w = -1;
+  eglglessink->render_region.h = -1;
+  eglglessink->render_region_changed = TRUE;
+  eglglessink->render_region_user = FALSE;
+
+  gst_eglglessink_set_render_rectangle (GST_VIDEO_OVERLAY (eglglessink), 100,
+      100, 100, 100);
 }
 
 /* entry point to initialize the plug-in
index caa4d246f032db3da8edd9b3783ba88f714396f3..55f475f0c791c67df8b6e0fc45ca29dab0759e1c 100644 (file)
@@ -183,10 +183,16 @@ struct _GstEglGlesSink
 {
   GstVideoSink videosink;       /* Element hook */
 
+  /* Region of the surface that should be rendered */
+  GstVideoRectangle render_region;
+  gboolean render_region_changed;
+  gboolean render_region_user;
+
+  /* Region of render_region that should be filled
+   * with the video frames */
   GstVideoRectangle display_region;
-  struct {
-    gint x, y, width, height;
-  } crop;
+
+  GstVideoRectangle crop;
   GstCaps *sinkcaps;
   GstCaps *current_caps, *configured_caps;
   GstVideoInfo configured_info;
index 67879eef0194c7a2f9954bed0ac8e2f303f57ebc..0d9b26d59732c3105964fe3475ad9b0b7930ca68 100644 (file)
@@ -73,7 +73,8 @@ platform_wrapper_init (void)
 }
 
 #ifdef HAVE_X11
-typedef struct {
+typedef struct
+{
   Display *display;
 } X11WindowData;