ges: Add a method to retrieve the 'natural' size of VideoSource
authorThibault Saunier <tsaunier@igalia.com>
Wed, 19 Feb 2020 21:06:26 +0000 (18:06 -0300)
committerThibault Saunier <tsaunier@igalia.com>
Wed, 26 Feb 2020 16:36:30 +0000 (13:36 -0300)
This way the user can easily know how the clip would look like
if no scaling was applied to the clip, this is useful to be able
to properly position the clips with the framepositionner element.

ges/ges-image-source.c
ges/ges-internal.h
ges/ges-video-source.c
ges/ges-video-source.h
ges/ges-video-test-source.c
ges/ges-video-uri-source.c

index b4c3eb4..206e36a 100644 (file)
@@ -171,6 +171,8 @@ ges_image_source_class_init (GESImageSourceClass * klass)
 
   GES_TIMELINE_ELEMENT_CLASS (klass)->set_inpoint = NULL;
   source_class->create_source = ges_image_source_create_source;
+  source_class->ABI.abi.get_natural_size =
+      ges_video_uri_source_get_natural_size;
 }
 
 static void
index 8afde95..87323f3 100644 (file)
@@ -459,6 +459,12 @@ typedef struct GESMultiFileURI
 
 G_GNUC_INTERNAL GESMultiFileURI * ges_multi_file_uri_new (const gchar * uri);
 
+/******************************
+ *  GESUriSource internal API *
+ ******************************/
+G_GNUC_INTERNAL gboolean
+ges_video_uri_source_get_natural_size(GESVideoSource* source, gint* width, gint* height);
+
 /************************
  * Our property masks   *
  ************************/
index 63ae963..3ba996c 100644 (file)
@@ -226,4 +226,33 @@ ges_video_source_init (GESVideoSource * self)
   self->priv = ges_video_source_get_instance_private (self);
   self->priv->positioner = NULL;
   self->priv->capsfilter = NULL;
+
+}
+
+/**
+ * ges_video_source_get_natural_size:
+ * @self: A #GESVideoSource
+ * @width: (out): The natural width of the underlying source
+ * @height: (out): The natural height of the underlying source
+ *
+ * Retrieves the natural size of the video stream. The natural size, is
+ * the size at which it will be displayed if no scaling is being applied.
+ *
+ * NOTE: The sources take into account the potential video rotation applied
+ * by the #videoflip element that is inside the source, effects applied on
+ * the clip which potentially also rotate the element are not taken into
+ * account.
+ *
+ * Returns: %TRUE if the object has a natural size, %FALSE otherwise.
+ */
+gboolean
+ges_video_source_get_natural_size (GESVideoSource * self, gint * width,
+    gint * height)
+{
+  GESVideoSourceClass *klass = GES_VIDEO_SOURCE_GET_CLASS (self);
+
+  if (!klass->ABI.abi.get_natural_size)
+    return FALSE;
+
+  return klass->ABI.abi.get_natural_size (self, width, height);
 }
index 1554cbd..f626b17 100644 (file)
@@ -85,12 +85,15 @@ struct _GESVideoSourceClass {
     struct {
       gboolean disable_scale_in_compositor;
       gboolean (*needs_converters)(GESVideoSource *self);
+      gboolean (*get_natural_size)(GESVideoSource* self, gint* width, gint* height);
     } abi;
   } ABI;
 };
 
 GES_API
 GType ges_video_source_get_type (void);
+GES_API
+gboolean ges_video_source_get_natural_size(GESVideoSource* self, gint* width, gint* height);
 
 G_END_DECLS
 
index a175dd5..ae9ae96 100644 (file)
@@ -43,12 +43,22 @@ G_DEFINE_TYPE_WITH_PRIVATE (GESVideoTestSource, ges_video_test_source,
 
 static GstElement *ges_video_test_source_create_source (GESTrackElement * self);
 
+static gboolean
+get_natural_size (GESVideoSource * source, gint * width, gint * height)
+{
+  *width = DEFAULT_WIDTH;
+  *height = DEFAULT_HEIGHT;
+
+  return TRUE;
+}
+
 static void
 ges_video_test_source_class_init (GESVideoTestSourceClass * klass)
 {
   GESVideoSourceClass *source_class = GES_VIDEO_SOURCE_CLASS (klass);
 
   source_class->create_source = ges_video_test_source_create_source;
+  source_class->ABI.abi.get_natural_size = get_natural_size;
 }
 
 static void
@@ -76,7 +86,11 @@ ges_video_test_source_create_source (GESTrackElement * self)
 
   elements = g_ptr_array_new ();
   g_ptr_array_add (elements, capsfilter);
-  caps = gst_caps_new_empty_simple ("video/x-raw");
+  caps = gst_caps_new_simple ("video/x-raw",
+      "width", G_TYPE_INT, DEFAULT_WIDTH,
+      "height", G_TYPE_INT, DEFAULT_HEIGHT,
+      "framerate", GST_TYPE_FRACTION, DEFAULT_FRAMERATE_N, DEFAULT_FRAMERATE_D,
+      NULL);
   g_object_set (capsfilter, "caps", caps, NULL);
   gst_caps_unref (caps);
 
index 468b94b..b10b458 100644 (file)
@@ -27,8 +27,9 @@
 #include "config.h"
 #endif
 
-#include <gst/pbutils/missing-plugins.h>
+#include <stdio.h>
 
+#include <gst/pbutils/missing-plugins.h>
 #include "ges-utils.h"
 #include "ges-internal.h"
 #include "ges-track-element.h"
@@ -113,6 +114,74 @@ ges_video_uri_source_needs_converters (GESVideoSource * source)
   return FALSE;
 }
 
+gboolean
+ges_video_uri_source_get_natural_size (GESVideoSource * source, gint * width,
+    gint * height)
+{
+  const GstTagList *tags = NULL;
+  gchar *rotation_info = NULL;
+  gint videoflip_method, rotate_angle;
+  GstDiscovererStreamInfo *info;
+  GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (source));
+
+  g_assert (GES_IS_URI_SOURCE_ASSET (asset));
+  info = ges_uri_source_asset_get_stream_info (GES_URI_SOURCE_ASSET (asset));
+
+  if (!GST_IS_DISCOVERER_VIDEO_INFO (info)) {
+    GST_ERROR_OBJECT (source, "Doesn't have a video info (%" GST_PTR_FORMAT
+        ")", info);
+    return FALSE;
+  }
+
+  *width =
+      gst_discoverer_video_info_get_width (GST_DISCOVERER_VIDEO_INFO (info));
+  *height =
+      gst_discoverer_video_info_get_height (GST_DISCOVERER_VIDEO_INFO (info));
+
+  if (!ges_timeline_element_lookup_child (GES_TIMELINE_ELEMENT (source),
+          "GstVideoFlip::video-direction", NULL, NULL))
+    goto done;
+
+  ges_timeline_element_get_child_properties (GES_TIMELINE_ELEMENT (source),
+      "GstVideoFlip::video-direction", &videoflip_method, NULL);
+
+  /* Rotating 90 degrees, either way, rotate */
+  if (videoflip_method == 1 || videoflip_method == 3)
+    goto rotate;
+
+  if (videoflip_method != 8)
+    goto done;
+
+  /* Rotation is automatic, we need to check if the media file is naturally
+     rotated */
+  tags =
+      gst_discoverer_stream_info_get_tags (GST_DISCOVERER_STREAM_INFO (info));
+  if (!tags)
+    goto done;
+
+  if (!gst_tag_list_get_string (tags, GST_TAG_IMAGE_ORIENTATION,
+          &rotation_info))
+    goto done;
+
+  if (sscanf (rotation_info, "rotate-%d", &rotate_angle) == 1) {
+    if (rotate_angle == 90 || rotate_angle == 270)
+      goto rotate;
+  }
+
+done:
+  g_free (rotation_info);
+  return TRUE;
+
+rotate:
+  GST_INFO_OBJECT (self, "Stream is rotated, taking that into account");
+  *width =
+      gst_discoverer_video_info_get_height (GST_DISCOVERER_VIDEO_INFO (info));
+  *height =
+      gst_discoverer_video_info_get_width (GST_DISCOVERER_VIDEO_INFO (info));
+
+  goto done;
+}
+
 /* Extractable interface implementation */
 
 static gchar *
@@ -218,6 +287,8 @@ ges_video_uri_source_class_init (GESVideoUriSourceClass * klass)
   source_class->create_source = ges_video_uri_source_create_source;
   source_class->ABI.abi.needs_converters =
       ges_video_uri_source_needs_converters;
+  source_class->ABI.abi.get_natural_size =
+      ges_video_uri_source_get_natural_size;
 }
 
 static void