vaapisink: allow scaling to ignore aspect ratio.
[platform/upstream/gstreamer-vaapi.git] / gst / vaapi / gstvaapisink.c
index 6e3b0c3..092169a 100644 (file)
@@ -158,6 +158,7 @@ enum {
     PROP_USE_GLX,
     PROP_USE_REFLECTION,
     PROP_ROTATION,
+    PROP_FORCE_ASPECT_RATIO,
 };
 
 #define DEFAULT_DISPLAY_TYPE            GST_VAAPI_DISPLAY_TYPE_ANY
@@ -381,6 +382,19 @@ gst_vaapisink_ensure_render_rect(GstVaapiSink *sink, guint width, guint height)
     if (!sink->caps)
         return TRUE;
 
+    if (!sink->keep_aspect) {
+        display_rect->width = width;
+        display_rect->height = height;
+        display_rect->x = 0;
+        display_rect->y = 0;
+
+        GST_DEBUG("force-aspect-ratio is false; distorting while scaling video");
+        GST_DEBUG("render rect (%d,%d):%ux%u",
+                  display_rect->x, display_rect->y,
+                  display_rect->width, display_rect->height);
+        return TRUE;
+    }
+
     GST_DEBUG("ensure render rect within %ux%u bounds", width, height);
 
     gst_vaapi_display_get_pixel_aspect_ratio(
@@ -673,13 +687,7 @@ gst_vaapisink_start(GstBaseSink *base_sink)
 {
     GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
 
-    if (!gst_vaapisink_ensure_display(sink))
-        return FALSE;
-
-    sink->uploader = gst_vaapi_uploader_new(sink->display);
-    if (!sink->uploader)
-        return FALSE;
-    return TRUE;
+    return gst_vaapisink_ensure_uploader(sink);
 }
 
 static gboolean
@@ -720,7 +728,17 @@ gst_vaapisink_get_caps_impl(GstBaseSink *base_sink)
 static inline GstCaps *
 gst_vaapisink_get_caps(GstBaseSink *base_sink, GstCaps *filter)
 {
-    return gst_vaapisink_get_caps_impl(base_sink);
+    GstCaps *caps, *out_caps;
+
+    caps = gst_vaapisink_get_caps_impl(base_sink);
+    if (caps && filter) {
+        out_caps = gst_caps_intersect_full(caps, filter,
+            GST_CAPS_INTERSECT_FIRST);
+        gst_caps_unref(caps);
+    }
+    else
+        out_caps = caps;
+    return out_caps;
 }
 #else
 #define gst_vaapisink_get_caps gst_vaapisink_get_caps_impl
@@ -885,6 +903,42 @@ render_reflection(GstVaapiSink *sink)
 }
 
 static gboolean
+gst_vaapisink_ensure_texture(GstVaapiSink *sink, GstVaapiSurface *surface)
+{
+    GstVideoRectangle tex_rect, dis_rect, out_rect;
+    guint width, height;
+
+    if (sink->texture)
+        return TRUE;
+
+    gst_vaapi_surface_get_size(surface, &width, &height);
+    tex_rect.x = 0;
+    tex_rect.y = 0;
+    tex_rect.w = width;
+    tex_rect.h = height;
+
+    gst_vaapi_display_get_size(sink->display, &width, &height);
+    dis_rect.x = 0;
+    dis_rect.y = 0;
+    dis_rect.w = width;
+    dis_rect.h = height;
+
+    gst_video_sink_center_rect(tex_rect, dis_rect, &out_rect, TRUE);
+
+    /* XXX: use surface size for now since some VA drivers have issues
+       with downscaling to the provided texture size. i.e. we should be
+       using the resulting out_rect size, which preserves the aspect
+       ratio of the surface */
+    width = tex_rect.w;
+    height = tex_rect.h;
+    GST_INFO("texture size %ux%u", width, height);
+
+    sink->texture = gst_vaapi_texture_new(sink->display,
+        GL_TEXTURE_2D, GL_BGRA, width, height);
+    return sink->texture != NULL;
+}
+
+static gboolean
 gst_vaapisink_show_frame_glx(
     GstVaapiSink               *sink,
     GstVaapiSurface            *surface,
@@ -897,17 +951,8 @@ gst_vaapisink_show_frame_glx(
     GLuint texture;
 
     gst_vaapi_window_glx_make_current(window);
-    if (!sink->texture) {
-        sink->texture = gst_vaapi_texture_new(
-            sink->display,
-            GL_TEXTURE_2D,
-            GL_BGRA,
-            sink->video_width,
-            sink->video_height
-        );
-        if (!sink->texture)
-            goto error_create_texture;
-    }
+    if (!gst_vaapisink_ensure_texture(sink, surface))
+        goto error_create_texture;
     if (!gst_vaapi_texture_put_surface(sink->texture, surface, flags))
         goto error_transfer_surface;
 
@@ -1224,6 +1269,9 @@ gst_vaapisink_set_property(
     case PROP_ROTATION:
         sink->rotation_req = g_value_get_enum(value);
         break;
+    case PROP_FORCE_ASPECT_RATIO:
+        sink->keep_aspect = g_value_get_boolean(value);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -1259,6 +1307,9 @@ gst_vaapisink_get_property(
     case PROP_ROTATION:
         g_value_set_enum(value, sink->rotation);
         break;
+    case PROP_FORCE_ASPECT_RATIO:
+        g_value_set_boolean(value, sink->keep_aspect);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -1370,6 +1421,21 @@ gst_vaapisink_class_init(GstVaapiSinkClass *klass)
                            GST_VAAPI_TYPE_ROTATION,
                            DEFAULT_ROTATION,
                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+    /**
+     * GstVaapiSink:force-aspect-ratio:
+     *
+     * When enabled, scaling respects video aspect ratio; when disabled, the
+     * video is distorted to fit the window.
+     */
+    g_object_class_install_property
+        (object_class,
+         PROP_FORCE_ASPECT_RATIO,
+         g_param_spec_boolean("force-aspect-ratio",
+                              "Force aspect ratio",
+                              "When enabled, scaling will respect original aspect ratio",
+                              TRUE,
+                              G_PARAM_READWRITE));
 }
 
 static void
@@ -1395,4 +1461,5 @@ gst_vaapisink_init(GstVaapiSink *sink)
     sink->use_reflection = FALSE;
     sink->use_overlay    = FALSE;
     sink->use_rotation   = FALSE;
+    sink->keep_aspect    = TRUE;
 }